From d506330cc72b55c552494ba911429ff3bc0dba0e Mon Sep 17 00:00:00 2001 From: davotoula Date: Fri, 10 Apr 2026 11:40:24 +0200 Subject: [PATCH] fix: move ContentResolver.getType off main thread in share intent consumer The DisposableEffect's OnNewIntentListener is invoked on the main thread when a new ACTION_SEND intent arrives (e.g. SwiftKey sharing a GIF). It called contentResolver.getType() synchronously, which can Binder-IPC to a remote content provider and block for tens to hundreds of milliseconds. Use rememberCoroutineScope() + scope.launch(Dispatchers.IO) since DisposableEffect has no coroutine scope of its own. The scope is tied to composition and cancels cleanly on disposal. Also fix a latent bug: the consumer read activity.intent instead of the intent parameter passed into the callback. activity.intent is the Activity's launch intent, not the new one that triggered the listener, so subsequent intents would reuse the first intent's URI. --- .../ui/screen/loggedIn/home/ShortNotePostScreen.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt index 58aa3fd82..f03d16590 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt @@ -55,6 +55,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -124,6 +125,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @OptIn(ExperimentalMaterial3Api::class, FlowPreview::class) @@ -144,6 +146,7 @@ fun ShortNotePostScreen( val context = LocalContext.current val activity = context.getActivity() + val scope = rememberCoroutineScope() LaunchedEffect(Unit) { postViewModel.initWritingAssistant(context) @@ -177,9 +180,12 @@ fun ShortNotePostScreen( postViewModel.addToMessage(it) } - IntentCompat.getParcelableExtra(activity.intent, Intent.EXTRA_STREAM, Uri::class.java)?.let { - val mediaType = context.contentResolver.getType(it) - postViewModel.selectImage(persistentListOf(SelectedMedia(it, mediaType))) + // Use the `intent` parameter (the new intent), not activity.intent (the launch intent). + IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java)?.let { uri -> + scope.launch(Dispatchers.IO) { + val mediaType = context.contentResolver.getType(uri) + postViewModel.selectImage(persistentListOf(SelectedMedia(uri, mediaType))) + } } } }