Skip to content

Commit d70be31

Browse files
WIP benchmarking ComposeWorkflow
1 parent 0860065 commit d70be31

File tree

19 files changed

+301
-3
lines changed

19 files changed

+301
-3
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
plugins {
2+
id("com.android.application")
3+
id("kotlin-android")
4+
id("android-sample-app")
5+
id("android-ui-tests")
6+
alias(libs.plugins.compose.compiler)
7+
}
8+
9+
android {
10+
defaultConfig {
11+
applicationId = "com.squareup.benchmark.composeworkflow.app"
12+
}
13+
namespace = "com.squareup.benchmark.composeworkflow.app"
14+
}
15+
16+
dependencies {
17+
debugImplementation(libs.squareup.leakcanary.android)
18+
19+
implementation(libs.androidx.activity.ktx)
20+
implementation(libs.androidx.lifecycle.viewmodel.ktx)
21+
implementation(libs.androidx.lifecycle.viewmodel.savedstate)
22+
implementation(libs.androidx.viewbinding)
23+
24+
implementation(project(":workflow-ui:core-android"))
25+
implementation(project(":workflow-ui:core-common"))
26+
27+
testImplementation(libs.kotlin.test.jdk)
28+
testImplementation(project(":workflow-testing"))
29+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<issues format="6" by="lint 7.4.1" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.1)" variant="all" version="7.4.1">
3+
4+
<issue
5+
id="DataExtractionRules"
6+
message="The attribute `android:allowBackup` is deprecated from Android 12 and higher and may be removed in future versions. Consider adding the attribute `android:dataExtractionRules` specifying an `@xml` resource which configures cloud backups and device transfers on Android 12 and higher."
7+
errorLine1=" android:allowBackup=&quot;false&quot;"
8+
errorLine2=" ~~~~~">
9+
<location
10+
file="src/main/AndroidManifest.xml"
11+
line="6"
12+
column="28"/>
13+
</issue>
14+
15+
</issues>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
4+
5+
<application
6+
android:allowBackup="false"
7+
android:label="@string/app_name"
8+
android:theme="@style/AppTheme"
9+
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon"
10+
>
11+
12+
<activity android:name="com.squareup.sample.hellocomposeworkflow.HelloComposeWorkflowActivity"
13+
android:exported="true">
14+
15+
<intent-filter>
16+
<action android:name="android.intent.action.MAIN" />
17+
<category android:name="android.intent.category.LAUNCHER" />
18+
</intent-filter>
19+
20+
</activity>
21+
22+
</application>
23+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.squareup.sample.hellocomposeworkflow
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.getValue
5+
import androidx.compose.runtime.mutableStateOf
6+
import androidx.compose.runtime.remember
7+
import androidx.compose.runtime.saveable.Saver
8+
import androidx.compose.runtime.saveable.SaverScope
9+
import androidx.compose.runtime.saveable.rememberSaveable
10+
import androidx.compose.runtime.setValue
11+
import com.squareup.sample.hellocomposeworkflow.HelloComposeWorkflow.State.Goodbye
12+
import com.squareup.sample.hellocomposeworkflow.HelloComposeWorkflow.State.Hello
13+
import com.squareup.workflow1.WorkflowExperimentalApi
14+
import com.squareup.workflow1.compose.ComposeWorkflow
15+
import java.util.concurrent.atomic.AtomicInteger
16+
17+
@OptIn(WorkflowExperimentalApi::class)
18+
object HelloComposeWorkflow : ComposeWorkflow<Unit, Nothing, HelloRendering>() {
19+
enum class State {
20+
Hello,
21+
Goodbye
22+
}
23+
24+
object StateSaver : Saver<State, Int> {
25+
override fun restore(value: Int) = State.entries[value]
26+
override fun SaverScope.save(value: State) = value.ordinal
27+
}
28+
29+
@Composable
30+
override fun produceRendering(
31+
props: Unit,
32+
emitOutput: (Nothing) -> Unit
33+
): HelloRendering {
34+
var state by rememberSaveable(stateSaver = StateSaver) { mutableStateOf(Hello) }
35+
val compositions = remember { AtomicInteger(0) }
36+
println("OMG recomposing state=$state (count=${compositions.incrementAndGet()})")
37+
38+
return HelloRendering(
39+
message = state.name,
40+
onClick = {
41+
println("OMG onClick! state=$state")
42+
state = when (state) {
43+
Hello -> Goodbye
44+
Goodbye -> Hello
45+
}
46+
}
47+
)
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
@file:OptIn(WorkflowExperimentalRuntime::class)
2+
3+
package com.squareup.sample.hellocomposeworkflow
4+
5+
import android.os.Bundle
6+
import androidx.activity.viewModels
7+
import androidx.appcompat.app.AppCompatActivity
8+
import androidx.lifecycle.SavedStateHandle
9+
import androidx.lifecycle.ViewModel
10+
import androidx.lifecycle.viewModelScope
11+
import com.squareup.workflow1.SimpleLoggingWorkflowInterceptor
12+
import com.squareup.workflow1.WorkflowExperimentalRuntime
13+
import com.squareup.workflow1.config.AndroidRuntimeConfigTools
14+
import com.squareup.workflow1.ui.renderWorkflowIn
15+
import com.squareup.workflow1.ui.workflowContentView
16+
import kotlinx.coroutines.flow.StateFlow
17+
18+
class HelloComposeWorkflowActivity : AppCompatActivity() {
19+
override fun onCreate(savedInstanceState: Bundle?) {
20+
super.onCreate(savedInstanceState)
21+
22+
// This ViewModel will survive configuration changes. It's instantiated
23+
// by the first call to viewModels(), and that original instance is returned by
24+
// succeeding calls.
25+
val model: HelloViewModel by viewModels()
26+
workflowContentView.take(lifecycle, model.renderings)
27+
}
28+
}
29+
30+
class HelloViewModel(savedState: SavedStateHandle) : ViewModel() {
31+
val renderings: StateFlow<HelloRendering> by lazy {
32+
renderWorkflowIn(
33+
workflow = HelloComposeWorkflow,
34+
scope = viewModelScope,
35+
savedStateHandle = savedState,
36+
runtimeConfig = AndroidRuntimeConfigTools.getAppWorkflowRuntimeConfig(),
37+
interceptors = listOf(SimpleLoggingWorkflowInterceptor())
38+
)
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.squareup.sample.hellocomposeworkflow
2+
3+
import com.squareup.sample.hellocomposeworkflow.databinding.HelloGoodbyeLayoutBinding
4+
import com.squareup.workflow1.ui.AndroidScreen
5+
import com.squareup.workflow1.ui.ScreenViewFactory
6+
import com.squareup.workflow1.ui.ScreenViewFactory.Companion.fromViewBinding
7+
8+
data class HelloRendering(
9+
val message: String,
10+
val onClick: () -> Unit
11+
) : AndroidScreen<HelloRendering> {
12+
override val viewFactory: ScreenViewFactory<HelloRendering> =
13+
fromViewBinding(HelloGoodbyeLayoutBinding::inflate) { r, _ ->
14+
helloMessage.text = r.message
15+
helloMessage.setOnClickListener { r.onClick() }
16+
}
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:orientation="vertical"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent">
6+
7+
<TextView
8+
android:id="@+id/hello_message"
9+
android:layout_width="match_parent"
10+
android:layout_height="match_parent"
11+
android:gravity="center"
12+
/>
13+
14+
</LinearLayout>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<resources>
2+
<string name="app_name">Compose Workflow Benchmark Target</string>
3+
</resources>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<resources>
2+
3+
<!-- Base application theme. -->
4+
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
5+
<!-- Customize your theme here. -->
6+
</style>
7+
8+
</resources>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import com.rickbusarow.kgx.libsCatalog
2+
import com.rickbusarow.kgx.version
3+
import com.squareup.workflow1.buildsrc.internal.javaTarget
4+
import com.squareup.workflow1.buildsrc.internal.javaTargetVersion
5+
6+
plugins {
7+
id("com.android.test")
8+
id("org.jetbrains.kotlin.android")
9+
}
10+
11+
// Note: We are not including our defaults from .buildscript as we do not need the base Workflow
12+
// dependencies that those include.
13+
14+
android {
15+
compileSdk = libsCatalog.version("compileSdk").toInt()
16+
17+
compileOptions {
18+
sourceCompatibility = javaTargetVersion
19+
targetCompatibility = javaTargetVersion
20+
}
21+
22+
kotlinOptions {
23+
jvmTarget = javaTarget
24+
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
25+
}
26+
27+
defaultConfig {
28+
minSdk = 28
29+
targetSdk = libsCatalog.version("targetSdk").toInt()
30+
31+
testInstrumentationRunner = "androidx.benchmark.junit4.AndroidBenchmarkRunner"
32+
}
33+
34+
buildTypes {
35+
create("release") {
36+
isDebuggable = false
37+
signingConfig = getByName("debug").signingConfig
38+
proguardFile("baseline-proguard-rules.pro")
39+
}
40+
}
41+
42+
targetProjectPath = ":benchmarks:compose-workflow:app"
43+
namespace = "com.squareup.benchmark.composeworkflow.benchmark"
44+
experimentalProperties["android.experimental.self-instrumenting"] = true
45+
}
46+
47+
dependencies {
48+
implementation(libs.androidx.benchmark)
49+
implementation(libs.androidx.test.espresso.core)
50+
implementation(libs.androidx.test.junit)
51+
implementation(libs.androidx.test.uiautomator)
52+
}
53+
54+
androidComponents {
55+
beforeVariants(selector().all()) {
56+
// TODO use it.enable when using AGP 7.3+
57+
it.enable = it.buildType == "release"
58+
}
59+
}

0 commit comments

Comments
 (0)