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.
This commit is contained in:
davotoula
2026-04-10 11:40:24 +02:00
parent 6aa949a4f4
commit d506330cc7
@@ -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)))
}
}
}
}