Skip to content

Commit aea3ca5

Browse files
committed
feat: add compose sample for adding state
1 parent 4a7d0bf commit aea3ca5

14 files changed

Lines changed: 236 additions & 28 deletions

File tree

JankStatsSample/app/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ android {
2525
release {
2626
minifyEnabled false
2727
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
28-
signingConfig signingConfigs.debug
2928
}
3029
}
3130
compileOptions {

JankStatsSample/app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
android:supportsRtl="true"
1111
android:theme="@style/Theme.JankStats">
1212

13-
<profileable android:shell="true" />
14-
1513
<activity
1614
android:name=".JankLoggingActivity"
1715
android:exported="true">

JankStatsSample/app/src/main/java/com/example/jankstats/JankLoggingActivity.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import androidx.navigation.fragment.NavHostFragment
2626
import androidx.navigation.ui.AppBarConfiguration
2727
import androidx.navigation.ui.navigateUp
2828
import androidx.navigation.ui.setupActionBarWithNavController
29+
import androidx.navigation.ui.setupWithNavController
2930
import com.example.jankstats.databinding.ActivityJankLoggingBinding
3031
import kotlinx.coroutines.Dispatchers
3132
import kotlinx.coroutines.asExecutor
@@ -100,6 +101,8 @@ class JankLoggingActivity : AppCompatActivity() {
100101
supportFragmentManager.findFragmentById(R.id.navigation_container) as NavHostFragment
101102
navController = navHostFragment.navController
102103

104+
binding.bottomNavigation.setupWithNavController(navController)
105+
103106
appBarConfiguration = AppBarConfiguration(navController.graph)
104107
setupActionBarWithNavController(navController, appBarConfiguration)
105108
}
@@ -108,7 +111,7 @@ class JankLoggingActivity : AppCompatActivity() {
108111
// [START state_navigation]
109112
val metricsStateHolder = PerformanceMetricsState.getForHierarchy(binding.root)
110113
// add current navigation information into JankStats state
111-
navController.addOnDestinationChangedListener { controller, destination, arguments ->
114+
navController.addOnDestinationChangedListener { _, destination, arguments ->
112115
metricsStateHolder.state?.addState(
113116
"Navigation",
114117
"Args(${arguments.toString()}), $destination"
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright 2022 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.jankstats.compose
18+
19+
import android.os.Bundle
20+
import android.view.LayoutInflater
21+
import android.view.View
22+
import android.view.ViewGroup
23+
import androidx.compose.foundation.background
24+
import androidx.compose.foundation.clickable
25+
import androidx.compose.foundation.layout.*
26+
import androidx.compose.foundation.lazy.LazyColumn
27+
import androidx.compose.foundation.lazy.rememberLazyListState
28+
import androidx.compose.material.Text
29+
import androidx.compose.runtime.Composable
30+
import androidx.compose.runtime.LaunchedEffect
31+
import androidx.compose.runtime.snapshotFlow
32+
import androidx.compose.ui.Alignment
33+
import androidx.compose.ui.Modifier
34+
import androidx.compose.ui.graphics.Color
35+
import androidx.compose.ui.platform.ComposeView
36+
import androidx.compose.ui.platform.ViewCompositionStrategy
37+
import androidx.compose.ui.tooling.preview.Preview
38+
import androidx.compose.ui.unit.dp
39+
import androidx.fragment.app.Fragment
40+
import androidx.navigation.findNavController
41+
import com.example.jankstats.R
42+
import com.example.jankstats.tools.simulateJank
43+
import kotlinx.coroutines.flow.collect
44+
45+
/**
46+
* Showcase how to work with JankStats from Compose.
47+
*/
48+
class ComposeListFragment : Fragment() {
49+
50+
override fun onCreateView(
51+
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
52+
): View {
53+
return ComposeView(requireContext()).apply {
54+
setViewCompositionStrategy(
55+
ViewCompositionStrategy.DisposeOnLifecycleDestroyed(viewLifecycleOwner)
56+
)
57+
58+
setContent {
59+
MessageList(onItemClick = {
60+
findNavController().navigate(R.id.action_composeList_to_messageContent)
61+
})
62+
}
63+
}
64+
}
65+
}
66+
67+
@Composable
68+
fun MessageList(onItemClick: () -> Unit) {
69+
val listState = rememberLazyListState()
70+
val metricsStateHolder = rememberMetricsStateHolder()
71+
72+
// Reporting scrolling state from compose should be done from side effect to prevent recomposition.
73+
LaunchedEffect(metricsStateHolder, listState) {
74+
snapshotFlow { listState.isScrollInProgress }.collect { isScrolling ->
75+
if (isScrolling) {
76+
metricsStateHolder.state?.addState("LazyList", "Scrolling")
77+
} else {
78+
metricsStateHolder.state?.removeState("LazyList")
79+
}
80+
}
81+
}
82+
83+
LazyColumn(state = listState) {
84+
items(100) { index ->
85+
MessageItem(index, onItemClick)
86+
}
87+
}
88+
}
89+
90+
91+
@Composable
92+
fun MessageItem(item: Int, onItemClick: () -> Unit) {
93+
Row(
94+
Modifier
95+
.fillMaxWidth()
96+
.clickable(onClick = onItemClick)
97+
.padding(16.dp),
98+
verticalAlignment = Alignment.CenterVertically
99+
) {
100+
Text("Message #$item", Modifier.padding(end = 16.dp))
101+
JankyComposable()
102+
}
103+
}
104+
105+
@Composable
106+
fun JankyComposable() {
107+
Box(
108+
Modifier
109+
.width(20.dp)
110+
.height(20.dp)
111+
.background(Color.Red)
112+
) {
113+
simulateJank()
114+
}
115+
}
116+
117+
@Preview(widthDp = 500)
118+
@Composable
119+
fun MessageListPreview() {
120+
MessageList(onItemClick = {})
121+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.example.jankstats.compose
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.remember
5+
import androidx.compose.ui.platform.LocalView
6+
import androidx.metrics.performance.PerformanceMetricsState
7+
8+
/**
9+
* Retrieve MetricsStateHolder from compose and remember until the current view changes.
10+
*/
11+
@Composable
12+
fun rememberMetricsStateHolder(): PerformanceMetricsState.MetricsStateHolder {
13+
val view = LocalView.current
14+
return remember(view) { PerformanceMetricsState.getForHierarchy(view) }
15+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector android:height="24dp" android:tint="#000000"
2+
android:viewportHeight="24" android:viewportWidth="24"
3+
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M12.87,11.81c-0.23,-0.38 -0.37,-0.83 -0.37,-1.31C12.5,9.12 13.62,8 15,8l1,0c1.51,0 2,-1 2,-1s0.55,6 -3,6c-0.49,0 -0.94,-0.14 -1.32,-0.38c-0.24,0.64 -0.59,1.76 -0.76,2.96c1.26,0.22 2.28,0.89 2.77,1.77c1.69,-1.17 2.81,-3.13 2.81,-5.35h3c0,5.24 -4.26,9.5 -9.5,9.5S2.5,17.24 2.5,12S6.76,2.5 12,2.5V0l4,4l-4,4V5.5c-3.58,0 -6.5,2.92 -6.5,6.5c0,2.21 1.11,4.17 2.81,5.35c0.51,-0.92 1.63,-1.62 2.98,-1.8c-0.09,-0.69 -0.26,-1.42 -0.49,-2.03C10.45,13.82 10,14 9.5,14c-1.1,0 -2,-0.9 -2,-2v-0.99c0,-0.56 -0.19,-1.09 -0.5,-1.51c0,0 4.45,-0.23 4.5,2.5c0,0.29 -0.06,0.56 -0.17,0.8C10.91,12.48 10.47,12.2 10,12c0.58,0.43 1.37,1.37 2,2.6c0.67,-1.62 1.68,-3.27 3,-4.6C14.24,10.52 13.53,11.12 12.87,11.81z"/>
5+
</vector>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<vector android:height="24dp" android:tint="#000000"
2+
android:viewportHeight="24" android:viewportWidth="24"
3+
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M13.7827,15.1719l2.1213,-2.1213l5.9962,5.9962l-2.1213,2.1213z"/>
5+
<path android:fillColor="@android:color/white" android:pathData="M17.5,10c1.93,0 3.5,-1.57 3.5,-3.5c0,-0.58 -0.16,-1.12 -0.41,-1.6l-2.7,2.7L16.4,6.11l2.7,-2.7C18.62,3.16 18.08,3 17.5,3C15.57,3 14,4.57 14,6.5c0,0.41 0.08,0.8 0.21,1.16l-1.85,1.85l-1.78,-1.78l0.71,-0.71L9.88,5.61L12,3.49c-1.17,-1.17 -3.07,-1.17 -4.24,0L4.22,7.03l1.41,1.41H2.81L2.1,9.15l3.54,3.54l0.71,-0.71V9.15l1.41,1.41l0.71,-0.71l1.78,1.78l-7.41,7.41l2.12,2.12L16.34,9.79C16.7,9.92 17.09,10 17.5,10z"/>
6+
</vector>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector android:height="24dp" android:tint="#000000"
2+
android:viewportHeight="24" android:viewportWidth="24"
3+
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M11.5,9C10.12,9 9,10.12 9,11.5s1.12,2.5 2.5,2.5 2.5,-1.12 2.5,-2.5S12.88,9 11.5,9zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM16.79,18.21l-2.91,-2.91c-0.69,0.44 -1.51,0.7 -2.39,0.7C9.01,16 7,13.99 7,11.5S9.01,7 11.5,7 16,9.01 16,11.5c0,0.88 -0.26,1.69 -0.7,2.39l2.91,2.9 -1.42,1.42z"/>
5+
</vector>

JankStatsSample/app/src/main/res/layout/activity_jank_logging.xml

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,20 @@
1414
limitations under the License.
1515
-->
1616

17-
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
17+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
1818
xmlns:app="http://schemas.android.com/apk/res-auto"
1919
xmlns:tools="http://schemas.android.com/tools"
2020
android:layout_width="match_parent"
2121
android:layout_height="match_parent"
2222
tools:context=".JankLoggingActivity">
2323

2424
<com.google.android.material.appbar.AppBarLayout
25-
android:layout_width="match_parent"
26-
android:layout_height="wrap_content">
25+
android:id="@+id/appbar"
26+
android:layout_width="0dp"
27+
android:layout_height="wrap_content"
28+
app:layout_constraintEnd_toEndOf="parent"
29+
app:layout_constraintStart_toStartOf="parent"
30+
app:layout_constraintTop_toTopOf="parent">
2731

2832
<androidx.appcompat.widget.Toolbar
2933
android:id="@+id/toolbar"
@@ -33,22 +37,25 @@
3337

3438
</com.google.android.material.appbar.AppBarLayout>
3539

36-
<androidx.constraintlayout.widget.ConstraintLayout
37-
android:layout_width="match_parent"
38-
android:layout_height="match_parent"
39-
app:layout_behavior="@string/appbar_scrolling_view_behavior">
40-
41-
<androidx.fragment.app.FragmentContainerView
42-
android:id="@+id/navigation_container"
43-
android:name="androidx.navigation.fragment.NavHostFragment"
44-
android:layout_width="0dp"
45-
android:layout_height="0dp"
46-
app:defaultNavHost="true"
47-
app:layout_constraintBottom_toBottomOf="parent"
48-
app:layout_constraintLeft_toLeftOf="parent"
49-
app:layout_constraintRight_toRightOf="parent"
50-
app:layout_constraintTop_toTopOf="parent"
51-
app:navGraph="@navigation/nav_graph" />
52-
</androidx.constraintlayout.widget.ConstraintLayout>
53-
54-
</androidx.coordinatorlayout.widget.CoordinatorLayout>
40+
<androidx.fragment.app.FragmentContainerView
41+
android:id="@+id/navigation_container"
42+
android:name="androidx.navigation.fragment.NavHostFragment"
43+
android:layout_width="0dp"
44+
android:layout_height="0dp"
45+
app:defaultNavHost="true"
46+
app:layout_constraintBottom_toTopOf="@id/bottom_navigation"
47+
app:layout_constraintLeft_toLeftOf="parent"
48+
app:layout_constraintRight_toRightOf="parent"
49+
app:layout_constraintTop_toBottomOf="@id/appbar"
50+
app:navGraph="@navigation/nav_graph" />
51+
52+
<com.google.android.material.bottomnavigation.BottomNavigationView
53+
android:id="@+id/bottom_navigation"
54+
android:layout_width="0dp"
55+
android:layout_height="wrap_content"
56+
app:layout_constraintBottom_toBottomOf="parent"
57+
app:layout_constraintEnd_toEndOf="parent"
58+
app:layout_constraintStart_toStartOf="parent"
59+
app:menu="@menu/bottom_menu" />
60+
61+
</androidx.constraintlayout.widget.ConstraintLayout>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
~ Copyright (C) The Android Open Source Project
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
-->
16+
<menu xmlns:android="http://schemas.android.com/apk/res/android">
17+
<item
18+
android:id="@+id/messageList"
19+
android:icon="@drawable/ic_views"
20+
android:title="@string/views" />
21+
22+
<item
23+
android:id="@+id/composeList"
24+
android:icon="@drawable/ic_compose"
25+
android:title="@string/compose" />
26+
27+
<item
28+
android:id="@+id/notImplemented"
29+
android:icon="@drawable/ic_construction"
30+
android:title="@string/not_implemented" />
31+
32+
</menu>

0 commit comments

Comments
 (0)