How to Get Activity From Jetpack Compose
Safely get current Activity in Composable
When working with Compose, there are often times when you need to get an Activity
. For example, I need an Activity
to call finish()
in a situation where the screen needs to close when a button is pressed. However, there is currently no built-in method for directly getting an Activity
in which composable is placed. In this article, I’m going to introduce 3 ways to get an Activity
in Compose.
LocalContext.current as Activity
The easiest and simplest way is LocalContext.current as Activity
. Just casting Context
to Activity
. In a way, this can be a very dangerous method. But I think it’s safe. To understand why this is a safe way to do this, we must first look at how LocalContext
is provided.
All composable start from ComponentActivity.setContent
, where all composition data(including LocalContext
) are initialized.
If you look at setContent
, ComposeView
is initialized with the Activity
that called setContent
through ComposeView(this)
. After that, the composition initialization process proceeds through ComposeView(this).setContent(content).
In that process, the ProvideAndroidCompositionLocals
function is called. You can see that most CompositionLocal
s are provided here, and LocalContext
is also provided. The owner
received as an argument becomes ComposeView
initialized with Activity
earlier, and the Context
is obtained from this ComposeView
and provided as LocalContext
.
Through this process, we can confirm that LocalContext
is passing the Activity
we called setContent
into the Context
, so LocalContext.current as Activity
is safe.
LocalActivity.current
However, casting the Context
to Activity
can still be awkward. In that case, can create a LocalActivity
and provide the Activity
directly to use.
Performance Optimization Tip:
Activity
instances do not change often or at all, so creating aCompositionLocal
withstaticCompositionLocalOf
eliminates the unnecessary process of tracking values change, which reduces overhead and optimizes performance.
setContent {
CompositionLocalProvider(LocalActivity provides this) {
composable()
}
}
Only need to provide provides
once before using composable, it is propagated, so composables with the same root can easily get Activity
through LocalActivity.current
.
Who knows how data is stored inside Compose, may be concerned about memory leaks by just putting Activity
into an array. (All composition data, including CompositionLocal
data, is managed in an Array<Any?>
array)
All composable have a process of erasing all data used by composable assigned to the Activity
if the Activity
disappears. So there is no memory leak.
Context.findActivity()
Finally, the method used by Google and the safest method.
This is the code being used in accompanist/permissions
and it is searching for Activity
while iterating in Context
. It throws when the Activity
is not found until the end, so it is a good method for those who want the strongest safety.
The End!
In this way, I have introduced three methods of get Activity
from Composable that I know of. If you have a better method or a method you are using, please share it in the comments!
Thanks for reading.
[View in Korean]
Reviewed by Gibson Ruitiari. thanks!