Skip to content

Commit 6461f8f

Browse files
authored
Wrap navigation actions with dropUnlessResumed (#225)
This commit updates `onClick` handlers across the sample app to use `androidx.lifecycle.compose.dropUnlessResumed`. This prevents multiple navigation events from being triggered simultaneously and ensures actions only occur when the lifecycle is in the `RESUMED` state. Changes include: * Wrapping `Button` and `clickable` actions in Basic, Material, and Scene recipes. * Applying the fix to DeepLink, ViewModel, and Modular (Hilt/Koin) samples. * Ensuring consistent navigation behavior across all Nav3 recipes to avoid double-tap issues. Fixes #107
1 parent cbc1787 commit 6461f8f

File tree

24 files changed

+83
-51
lines changed

24 files changed

+83
-51
lines changed

app/src/main/java/com/example/nav3recipes/RecipePickerActivity.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import androidx.compose.runtime.Composable
4141
import androidx.compose.ui.Modifier
4242
import androidx.compose.ui.text.font.FontWeight
4343
import androidx.compose.ui.unit.dp
44+
import androidx.lifecycle.compose.dropUnlessResumed
4445
import com.example.nav3recipes.animations.AnimatedActivity
4546
import com.example.nav3recipes.basic.BasicActivity
4647
import com.example.nav3recipes.basicdsl.BasicDslActivity
@@ -153,9 +154,9 @@ class RecipePickerActivity : ComponentActivity() {
153154
is Recipe -> {
154155
ListItem(
155156
headlineContent = { Text(item.name) },
156-
modifier = Modifier.clickable {
157+
modifier = Modifier.clickable(onClick = dropUnlessResumed {
157158
item.start()
158-
}
159+
})
159160
)
160161
}
161162
is Heading -> {

app/src/main/java/com/example/nav3recipes/animations/AnimatedActivity.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import androidx.compose.animation.slideOutVertically
1414
import androidx.compose.animation.togetherWith
1515
import androidx.compose.material3.Button
1616
import androidx.compose.material3.Text
17+
import androidx.lifecycle.compose.dropUnlessResumed
1718
import androidx.navigation3.runtime.NavKey
1819
import androidx.navigation3.runtime.entryProvider
1920
import androidx.navigation3.runtime.rememberNavBackStack
@@ -50,14 +51,14 @@ class AnimatedActivity : ComponentActivity() {
5051
entryProvider = entryProvider {
5152
entry<ScreenA> {
5253
ContentOrange("This is Screen A") {
53-
Button(onClick = { backStack.add(ScreenB) }) {
54+
Button(onClick = dropUnlessResumed { backStack.add(ScreenB) }) {
5455
Text("Go to Screen B")
5556
}
5657
}
5758
}
5859
entry<ScreenB> {
5960
ContentMauve("This is Screen B") {
60-
Button(onClick = { backStack.add(ScreenC) }) {
61+
Button(onClick = dropUnlessResumed { backStack.add(ScreenC) }) {
6162
Text("Go to Screen C")
6263
}
6364
}

app/src/main/java/com/example/nav3recipes/basic/BasicActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import androidx.compose.material3.Button
2323
import androidx.compose.material3.Text
2424
import androidx.compose.runtime.mutableStateListOf
2525
import androidx.compose.runtime.remember
26+
import androidx.lifecycle.compose.dropUnlessResumed
2627
import androidx.navigation3.runtime.NavEntry
2728
import androidx.navigation3.ui.NavDisplay
2829
import com.example.nav3recipes.content.ContentBlue
@@ -48,7 +49,7 @@ class BasicActivity : ComponentActivity() {
4849
when (key) {
4950
is RouteA -> NavEntry(key) {
5051
ContentGreen("Welcome to Nav3") {
51-
Button(onClick = {
52+
Button(onClick = dropUnlessResumed {
5253
backStack.add(RouteB("123"))
5354
}) {
5455
Text("Click to navigate")

app/src/main/java/com/example/nav3recipes/basicdsl/BasicDslActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.activity.ComponentActivity
2121
import androidx.activity.compose.setContent
2222
import androidx.compose.material3.Button
2323
import androidx.compose.material3.Text
24+
import androidx.lifecycle.compose.dropUnlessResumed
2425
import androidx.navigation3.runtime.NavKey
2526
import androidx.navigation3.runtime.entryProvider
2627
import androidx.navigation3.runtime.rememberNavBackStack
@@ -50,7 +51,7 @@ class BasicDslActivity : ComponentActivity() {
5051
entryProvider = entryProvider {
5152
entry<RouteA> {
5253
ContentGreen("Welcome to Nav3") {
53-
Button(onClick = {
54+
Button(onClick = dropUnlessResumed {
5455
backStack.add(RouteB("123"))
5556
}) {
5657
Text("Click to navigate")

app/src/main/java/com/example/nav3recipes/basicsaveable/BasicSaveableActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.activity.ComponentActivity
2121
import androidx.activity.compose.setContent
2222
import androidx.compose.material3.Button
2323
import androidx.compose.material3.Text
24+
import androidx.lifecycle.compose.dropUnlessResumed
2425
import androidx.navigation3.runtime.NavEntry
2526
import androidx.navigation3.runtime.NavKey
2627
import androidx.navigation3.runtime.rememberNavBackStack
@@ -51,7 +52,7 @@ class BasicSaveableActivity : ComponentActivity() {
5152
when (key) {
5253
is RouteA -> NavEntry(key) {
5354
ContentGreen("Welcome to Nav3") {
54-
Button(onClick = {
55+
Button(onClick = dropUnlessResumed {
5556
backStack.add(RouteB("123"))
5657
}) {
5758
Text("Click to navigate")

app/src/main/java/com/example/nav3recipes/bottomsheet/BottomSheetActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import androidx.compose.runtime.remember
2727
import androidx.compose.ui.Modifier
2828
import androidx.compose.ui.draw.clip
2929
import androidx.compose.ui.unit.dp
30+
import androidx.lifecycle.compose.dropUnlessResumed
3031
import androidx.navigation3.runtime.NavKey
3132
import androidx.navigation3.runtime.entryProvider
3233
import androidx.navigation3.runtime.rememberNavBackStack
@@ -59,7 +60,7 @@ class BottomSheetActivity : ComponentActivity() {
5960
entryProvider = entryProvider {
6061
entry<RouteA> {
6162
ContentGreen("Welcome to Nav3") {
62-
Button(onClick = {
63+
Button(onClick = dropUnlessResumed {
6364
backStack.add(RouteB("123"))
6465
}) {
6566
Text("Click to open bottom sheet")

app/src/main/java/com/example/nav3recipes/commonui/CommonUiActivity.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import androidx.compose.runtime.remember
3636
import androidx.compose.runtime.setValue
3737
import androidx.compose.runtime.snapshots.SnapshotStateList
3838
import androidx.compose.ui.graphics.vector.ImageVector
39+
import androidx.lifecycle.compose.dropUnlessResumed
3940
import androidx.navigation3.runtime.entryProvider
4041
import androidx.navigation3.ui.NavDisplay
4142
import com.example.nav3recipes.content.ContentBlue
@@ -92,7 +93,9 @@ class CommonUiActivity : ComponentActivity() {
9293
}
9394
entry<ChatList>{
9495
ContentGreen("Chat list screen"){
95-
Button(onClick = { topLevelBackStack.add(ChatDetail) }) {
96+
Button(onClick = dropUnlessResumed {
97+
topLevelBackStack.add(ChatDetail)
98+
}) {
9699
Text("Go to conversation")
97100
}
98101
}

app/src/main/java/com/example/nav3recipes/conditional/ConditionalActivity.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import androidx.compose.runtime.mutableStateOf
2929
import androidx.compose.runtime.remember
3030
import androidx.compose.runtime.saveable.rememberSaveable
3131
import androidx.compose.runtime.saveable.rememberSerializable
32+
import androidx.lifecycle.compose.dropUnlessResumed
3233
import androidx.navigation3.runtime.NavBackStack
3334
import androidx.navigation3.runtime.NavKey
3435
import androidx.navigation3.runtime.entryProvider
@@ -100,18 +101,18 @@ class ConditionalActivity : ComponentActivity() {
100101
entry<Home> {
101102
ContentGreen("Welcome to Nav3. Logged in? ${isLoggedIn}") {
102103
Column {
103-
Button(onClick = { navigator.navigate(Profile) }) {
104+
Button(onClick = dropUnlessResumed { navigator.navigate(Profile) }) {
104105
Text("Profile")
105106
}
106-
Button(onClick = { navigator.navigate(Login()) }) {
107+
Button(onClick = dropUnlessResumed { navigator.navigate(Login()) }) {
107108
Text("Login")
108109
}
109110
}
110111
}
111112
}
112113
entry<Profile> {
113114
ContentBlue("Profile screen (only accessible once logged in)") {
114-
Button(onClick = {
115+
Button(onClick = dropUnlessResumed {
115116
isLoggedIn = false
116117
navigator.navigate(Home)
117118
}) {
@@ -121,7 +122,7 @@ class ConditionalActivity : ComponentActivity() {
121122
}
122123
entry<Login> { key ->
123124
ContentYellow("Login screen. Logged in? $isLoggedIn") {
124-
Button(onClick = {
125+
Button(onClick = dropUnlessResumed {
125126
isLoggedIn = true
126127
key.redirectToKey?.let { targetKey ->
127128
backStack.remove(key)

app/src/main/java/com/example/nav3recipes/deeplink/advanced/AdvancedCreateDeepLinkActivity.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.compose.runtime.mutableStateOf
99
import androidx.compose.runtime.remember
1010
import androidx.compose.runtime.setValue
1111
import androidx.core.net.toUri
12+
import androidx.lifecycle.compose.dropUnlessResumed
1213
import com.example.nav3recipes.deeplink.common.EntryScreen
1314
import com.example.nav3recipes.deeplink.common.LIST_FIRST_NAMES
1415
import com.example.nav3recipes.deeplink.common.LIST_LOCATIONS
@@ -86,7 +87,7 @@ class AdvancedCreateDeepLinkActivity: ComponentActivity() {
8687
TextContent(intentString)
8788

8889
// deeplink to target
89-
PaddedButton("Deeplink Away!") {
90+
PaddedButton("Deeplink Away!", onClick = dropUnlessResumed {
9091
val intent = Intent().apply {
9192
data = finalUrl.toUri()
9293
action = Intent.ACTION_VIEW
@@ -96,7 +97,7 @@ class AdvancedCreateDeepLinkActivity: ComponentActivity() {
9697
}
9798

9899
startActivity(intent)
99-
}
100+
})
100101
}
101102
}
102103
}

app/src/main/java/com/example/nav3recipes/deeplink/basic/CreateDeepLinkActivity.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import androidx.compose.runtime.mutableStateOf
1111
import androidx.compose.runtime.remember
1212
import androidx.compose.runtime.setValue
1313
import androidx.core.net.toUri
14+
import androidx.lifecycle.compose.dropUnlessResumed
1415
import com.example.nav3recipes.deeplink.common.PaddedButton
1516
import com.example.nav3recipes.deeplink.common.EMPTY
1617
import com.example.nav3recipes.deeplink.common.EntryScreen
@@ -149,15 +150,15 @@ class CreateDeepLinkActivity : ComponentActivity() {
149150
val finalUrl = "${PATH_BASE}/${selectedPath.value}$arguments"
150151
TextContent("Final url:\n$finalUrl")
151152
// deeplink to target
152-
PaddedButton("Deeplink Away!") {
153+
PaddedButton("Deeplink Away!", onClick = dropUnlessResumed {
153154
val intent = Intent(
154155
this@CreateDeepLinkActivity,
155156
MainActivity::class.java
156157
)
157158
// start activity with the url
158159
intent.data = finalUrl.toUri()
159160
startActivity(intent)
160-
}
161+
})
161162
}
162163
}
163164
}

0 commit comments

Comments
 (0)