Gibt es eine Möglichkeit, die aktuelle Aktivität in der Compose-Funktion abzurufen?
@Composable
fun CameraPreviewScreen() {
val context = ContextAmbient.current
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this, MainActivity.REQUIRED_PERMISSIONS, MainActivity.REQUEST_CODE_PERMISSIONS // get activity for `this`
)
return
}
}
Während die vorherige Antwort (das ist ContextWrapper
-aware) in der Tat die richtige ist, möchte ich eine idiomatischere Implementierung zum Kopieren und Einfügen bereitstellen.
fun Context.getActivity(): AppCompatActivity? = when (this) {
is AppCompatActivity -> this
is ContextWrapper -> baseContext.getActivity()
else -> null
}
Wie ContextWrapper
s können sich unmöglich gegenseitig umwickeln von Bedeutung Rekursion ist hier in Ordnung.
Um den Kontext zu bekommen
val context = LocalContext.current
Rufen Sie dann die Aktivität mithilfe des Kontexts ab. Erstellen Sie eine Erweiterungsfunktion und rufen Sie diese Erweiterungsfunktion mit Ihrem Kontext wie auf context.getActivity().
fun Context.getActivity(): AppCompatActivity? {
var currentContext = this
while (currentContext is ContextWrapper) {
if (currentContext is AppCompatActivity) {
return currentContext
}
currentContext = currentContext.baseContext
}
return null
}

Abdelila El Aissaoui
Sie können die Aktivität aus Ihren Composables abrufen, indem Sie den Kontext umwandeln (ich habe keinen einzigen Fall gefunden, in dem der Kontext nicht die Aktivität war). Wie Jim jedoch erwähnt hat, ist dies keine gute Praxis.
val activity = LocalContext.current as Activity
Persönlich verwende ich es, wenn ich nur mit Code herumspiele, der die Aktivität erfordert (Berechtigungen sind ein gutes Beispiel), aber sobald ich es zum Laufen gebracht habe, verschiebe ich es einfach in die Aktivität und verwende Parameter/Callback.
Bearbeiten: Wie in den Kommentaren erwähnt, kann die Verwendung im Produktionscode gefährlich sein, da es abstürzen kann, da Current ein Kontext-Wrapper ist. Mein Vorschlag dient hauptsächlich zum Testen von Code.
Verwenden Sie zum Anfordern der Laufzeitberechtigung in Jetpack Compose die Begleitbibliothek: https://github.com/google/accompanist/tree/main/permissions
Anwendungsbeispiel aus Dokumente:
@Composable
private fun FeatureThatRequiresCameraPermission(
navigateToSettingsScreen: () -> Unit
) {
// Track if the user doesn't want to see the rationale any more.
var doNotShowRationale by rememberSaveable { mutableStateOf(false) }
val cameraPermissionState = rememberPermissionState(android.Manifest.permission.CAMERA)
PermissionRequired(
permissionState = cameraPermissionState,
permissionNotGrantedContent = {
if (doNotShowRationale) {
Text("Feature not available")
} else {
Column {
Text("The camera is important for this app. Please grant the permission.")
Spacer(modifier = Modifier.height(8.dp))
Row {
Button(onClick = { cameraPermissionState.launchPermissionRequest() }) {
Text("Ok!")
}
Spacer(Modifier.width(8.dp))
Button(onClick = { doNotShowRationale = true }) {
Text("Nope")
}
}
}
}
},
permissionNotAvailableContent = {
Column {
Text(
"Camera permission denied. See this FAQ with information about why we " +
"need this permission. Please, grant us access on the Settings screen."
)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = navigateToSettingsScreen) {
Text("Open Settings")
}
}
}
) {
Text("Camera permission Granted")
}
}
Wenn Sie die Quelle überprüfen, werden Sie das auch herausfinden Google verwendet dieselbe Problemumgehung wie in der Antwort von Rajeev angegeben, daher ist Jims Antwort auf schlechte Praktiken etwas umstritten.
Anstatt die zu werfen Context
zu einem Activity
können Sie es sicher verwenden, indem Sie eine erstellen LocalActivity
.
val LocalActivity = staticCompositionLocalOf<ComponentActivity> {
noLocalProvidedFor("LocalActivity")
}
private fun noLocalProvidedFor(name: String): Nothing {
error("CompositionLocal $name not present")
}
Verwendungszweck:
CompositionLocalProvider(LocalActivity provides this) {
val activity = LocalActivity.current
// your content
}

Jim
Das Abrufen einer Aktivität aus einer Composable-Funktion gilt als schlechte Vorgehensweise, da Ihre Composables nicht eng mit dem Rest Ihrer App gekoppelt sein sollten. Unter anderem wird eine enge Kopplung Sie daran hindern, Ihr Composable zu testen, und die Wiederverwendung im Allgemeinen erschweren.
Wenn Sie sich Ihren Code ansehen, sieht es so aus, als würden Sie Berechtigungen innerhalb des Composable anfordern. Auch dies möchten Sie nicht in Ihrem Composable tun, da Composable-Funktionen so oft wie in jedem Frame ausgeführt werden können, was bedeutet, dass Sie diese Funktion in jedem Frame aufrufen würden.
Richten Sie stattdessen Ihre Kameraberechtigungen in Ihrer Aktivität ein und geben Sie (über Parameter) alle Informationen weiter, die von Ihrem Composable benötigt werden, um Pixel zu rendern.

Val Okafor
Unten finden Sie eine geringfügige Änderung der @Jeffset-Antwort, da Compose-Aktivitäten auf ComponentActivity und nicht auf AppCompatActivity basieren.
fun Context.getActivity(): ComponentActivity? = when (this) {
is ComponentActivity -> this
is ContextWrapper -> baseContext.findActivity()
else -> null
}
10174200cookie-checkSo erhalten Sie Aktivität in Composingyes