I need to automatically refresh an Android Compose screen when the app returns to the foreground.
I have an that requires permissions and location services.
If the user has switched any of these off a list is drawn of the items that need to be changed. When the user goes to Settings and the app returns to the foreground I would like the list to refresh to reflect the changes.
I am using Compose and Compose navigation. I have looked and I can't figure out the equivalent of onResume lifecycle event that could be used to trigger the refresh.
Any ideas would be gratefully received as I am at a loss.
Using official API (requires Lifecycle Runtime Compose 2.7.0):
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.7.0")
The official way to detect Lifecycle.State
changes would be using the following code snippet:
val lifecycleOwner = LocalLifecycleOwner.current
val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
LaunchedEffect(lifecycleState) {
// Do something with your state
// You may want to use DisposableEffect or other alternatives
// instead of LaunchedEffect
when (lifecycleState) {
Lifecycle.State.DESTROYED -> {}
Lifecycle.State.INITIALIZED -> {}
Lifecycle.State.CREATED -> {}
Lifecycle.State.STARTED -> {}
Lifecycle.State.RESUMED -> {}
}
}
collectStateAsState
is a convenience extension function that collects State changes by using Lifecycle's new property currentStateFlow
. So the code above would be the same as doing:
val lifecycleOwner = LocalLifecycleOwner.current
val state by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
LaunchedEffect(state) {
// Do something with your state
// You may want to use DisposableEffect or other alternatives
// instead of LaunchedEffect
}
Remember to import androidx.compose.runtime.getValue
to access directly the Lifecycle.State
.
As mentioned by @HåkonSchia, you can also use variations of DiposableEffect that also take in consideration the Lifecycle:
LifecycleStartEffect(Unit) {
// Do something on start or launch effect
onStopOrDispose {
// Do something on stop or dispose effect
}
}
LifecycleResumeEffect(Unit) {
// Do something on resume or launch effect
onPauseOrDispose {
// Do something on pause or dispose effect
}
}
Old answer:
Compose is not aware of state changes like onPause
or onResume
, you have to handle it using the parent activity's methods.
An example would be a LiveData
instance in your activity that updates each time onResume
is executed and observe it as a state in your main parent composable.
Let's take a look at the following example:
class MainActivity : AppCompatActivity() {
// Use whatever type your prefer/require, this is just an example
private val exampleLiveData = MutableLiveData("")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// Your main composable
MyApplicationTheme {
// Save the state into a variable otherwise it won't work
val state = exampleLiveData.observeAsState()
Log.d("EXAMPLE", "Recomposing screen - ${state.value}")
Surface(color = MaterialTheme.colors.background) {
Greeting("Android")
}
}
}
}
override fun onResume() {
super.onResume()
// Save whatever you want in your live data, this is just an example
exampleLiveData.value = DateTimeFormatter.ISO_INSTANT.format(Instant.now())
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MyApplicationTheme {
Greeting("Android")
}
}
As you can see in this example, I have a LiveData
property in my activity that containts a String. Whenever onResume
is executed the property is updated with the new timestamp and the observing composable is recomposed.