Reputation: 167
In a simple example, how to access the Exit event of our app, without using ViewModel or Hilt, etc.?
For example, to display a simple Toast message, while we exit the app.
The following code, when we press the back button to exit, works properly, and displays the toast:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var ctx = applicationContext
setContent {
checkExit(ctx)
}
}
}
@Composable
fun checkExit(ctx: Context) {
DisposableEffect(""){
onDispose {
Toast.makeText(ctx, "onExit", Toast.LENGTH_LONG).show()
}
}
}
But if we minimize the app and then exit by swiping up the screen in the background, this toast will no longer be displayed
**Working Code, thanks to AgentP**
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var ctx = applicationContext
setContent {
val lifecycle: LifecycleOwner = LocalLifecycleOwner.current
checkExit(ctx, lifecycle)
}
}
}
@Composable
fun checkExit(ctx: Context, lifecycle: LifecycleOwner) {
DisposableEffect(Unit) {
val observer = LifecycleEventObserver { _, event ->
when(event){
Lifecycle.Event.ON_STOP -> {
Toast.makeText(ctx, "onExit", Toast.LENGTH_SHORT).show()
}
}
}
lifecycle.lifecycle.addObserver(observer)
onDispose {
lifecycle.lifecycle.removeObserver(observer)
}
}
}
Upvotes: 5
Views: 4375
Reputation: 7250
To understand the problem here you need to understand about Side-Effects in compose
What is DisposableEffect?
A side effect of composition that must run for any new unique value of key1 and must be reversed or cleaned up if key1 changes or if the DisposableEffect leaves the composition.
Basically, It will run
In this case, it is happening for a second reason i.e it is causing due to its exit from composition
But why is it working when you back press and why not working when you kill app from recent?
To understand this in a better way read onDispose callback not called when app is killed
To quote from the answer to the above question
Composer is
disposed
whenviewLifecycle
is inON_DESTROY
state. IfON_DESTROY
is not dispatched, the composer will not dispose
So basically what happening is the composition will not dispose if it fails to receive the ON_DESTORY
from the lifecycle
It's not safe to call anything in onDispose unless you are removing some observers and all.
How to fix this?
You can use below code
DisposableEffect(Unit) {
val observer = LifecycleEventObserver { lifecycleOwner, event ->
when(event){
Lifecycle.Event.ON_STOP,Lifecycle.Event.ON_DESTROY -> {
checkCtx()
}
}
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
The obve code sets an observer for lifecycle events and calls the method checkCtx()
when we lifecycle gets ON_DESTROY
or ON_STOP
as state
checkCtx() : Note its not a composable function it should reside in activity/fragment
private fun checkCtx() {
Toast.makeText(this, "onExit", Toast.LENGTH_LONG).show()
}
Upvotes: 7