I'm having a little bit of an headache with several applications in Kotlin - Compose; I'll go straight to the point:
The issue is consistently happening (9 times out of 10) with Xiaomi devices running API 29. The device that I currently have available (and that also presents that issue) is a Xiaomi Mi A2 Lite.
Emulator: Running the application in an emulator (API 29) works without any problem
Manifest: Manifest has the following permissions:
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
Provider paths:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-cache-path
name="my_files_cached"
path="." />
<files-path
name="my_files"
path="."/>
</paths>
Runtime permissions: Runtime permissions are given in both camera & file picker components when clicking a button (see code snippets in Code section).
ActivityResultContracts.TakePicture()
or
ActivityResultContracts.GetContent()
--- PROCESS ENDED (16504) for package ... ----
signaling that the app has been killed in the backgroundBelow a snippet of a @Composable
body for handling the Camera photo snapping (I'm not posting the file picker code to avoid a text-wall; consider that it's similiar to the camera one):
val tmpFile = createTmpExtCachePhoto(photoFileName)
val context = LocalContext.current
var currentPhotoUri by remember { mutableStateOf(value = Uri.EMPTY) }
val uri = FileProvider.getUriForFile(
Objects.requireNonNull(context),
BuildConfig.APPLICATION_ID + ".provider", tmpFile
)
val cameraLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.TakePicture(),
onResult = { success ->
if (success) currentPhotoUri = uri
}
)
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// Permission Accepted: Do something
cameraLauncher.launch(uri)
} else {
// Permission Denied: Do something
onCameraPermissionDenied.invoke()
}
}
if (currentPhotoUri.toString().isNotEmpty()) {
onImagePicked.invoke(currentPhotoUri.toString())
}
Button(
modifier = modifier,
colors = buttonColors,
onClick = {
// Check permission
when (PackageManager.PERMISSION_GRANTED) {
ContextCompat.checkSelfPermission(
context,
Manifest.permission.CAMERA
) -> {
// Permission already given, perform operation
cameraLauncher.launch(uri)
}
else -> {
// Asking for permission
launcher.launch(Manifest.permission.CAMERA)
}
}
}
) {
Text(text = buttonLabel)
}
From what I got I think that there shouldn't be a particular issue within my codebase and this whole ordeal seems like it's coming from the system beneath that kills the app immediatelly after it goes out of focus. Now, if that happens to be the case, how should this situation be handled? Is there something that I can do to solve the problem? I'm willing to evaluate even workaround solutions that gets the app into a stable and reliable situation.
With that being said, thank you for your time!
Thanks to CommonsWare and Alexander Hoffmann comments I ended up solving the problem by making use of what the Android framework and Compose already gives us in terms of handling and persisting state throughout system-initiated process death:
This is a very useful page on developer.android that I heartily recommend. It describes the various possibilities that we have when talking about saving UI states.
With that being said I hope that this will be useful and thank you all once again for your time!