Skip to content

Instantly share code, notes, and snippets.

@micHar
Created October 28, 2021 06:41
Show Gist options
  • Save micHar/716d810f319973beb86ebbb1a5257be8 to your computer and use it in GitHub Desktop.
Save micHar/716d810f319973beb86ebbb1a5257be8 to your computer and use it in GitHub Desktop.
/**
* Sets the result to be obtained by [NavResultCallback] attached to [targetBackStackEntry]
*/
abstract class NavResultPusher<T>(
private val targetBackStackEntry: NavBackStackEntry,
private val key: String
) {
open fun setResult(result: T) = targetBackStackEntry.savedStateHandle.set(key, result)
}
/**
* Observes results passed from a nav destination to this [NavBackStackEntry].
* Delivers the result [ON_RESUME] to handle both fullscreen and dialog origins.
*
* Alternative to savedStateHandle.getLiveData which redelivers the old value despite it being cleared
* and which doesn't handle dialog destinations well
* (see: https://developer.android.com/guide/navigation/navigation-programmatic#additional_considerations)
*/
abstract class NavResultCallback<T>(
private val currentBackStackEntry: NavBackStackEntry,
private val key: String
) {
private val flow = MutableStateFlow<T?>(null)
open fun observeResult(): Flow<T?> {
val observer = LifecycleEventObserver { _, event ->
if (event == ON_RESUME && currentBackStackEntry.savedStateHandle.contains(key)) {
flow.tryEmit(currentBackStackEntry.savedStateHandle.get<T>(key)!!)
}
}
return flow
.onStart { currentBackStackEntry.lifecycle.addObserver(observer) }
.onCompletion { currentBackStackEntry.lifecycle.removeObserver(observer) }
}
fun clearResult() {
currentBackStackEntry.savedStateHandle.remove<Boolean>(key)
flow.tryEmit(null)
}
}
// ===USAGE===
private const val DELETED_ID = "deleted_id"
//this should be injected into the viewmodel of the the Composable started for result, e.g. some DeleteItemScreen
//when the item is deleted and just before popBackStack, the viewmodel should call pusher.setResult(deletedId)
class DeletedIdResultPusher(
targetBackStackEntry: NavBackStackEntry
) : NavResultPusher<String>(targetBackStackEntry, DELETED_ID)
//this should be injected into the viewmodel of the the Composable that navigates to DeleteItemScreen for result
//it can e.g. callback.observeResult().collectAsState in the composable to show a Snackbar and when the snackbar is dimissed
//it can call callback.clear() to get rid of the result
class DeletedIdResultCallback(
currentBackStackEntry: NavBackStackEntry
) : NavResultCallback<String>(currentBackStackEntry, DELETED_ID)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment