Einleitung: Warum Context in Jetpack Compose eine Kopfschmerzquelle für Anfänger ist
\nWenn Sie jemals mit XML für Android entwickelt haben, wissen Sie, dass Context buchstäblich der „Schlüssel“ zu allem ist: vom Zugriff auf Ressourcen bis zum Starten neuer Activities. Aber wenn Sie zu Jetpack Compose wechseln, ändert sich alles. Komposable Funktionen haben keinen direkten Zugriff auf Context, und das wird oft zu einem Stolperstein für Entwickler, insbesondere für diejenigen, die gerade erst mit dem deklarativen Ansatz beginnen.
Die Frage „How to get Context in Jetpack Compose“ auf Stack Overflow hat Tausende von Aufrufen und Dutzende von Antworten gesammelt. Das ist kein Zufall. In diesem Artikel werden wir alle möglichen Methoden untersuchen, um Context in Compose zu erhalten, von einfachen bis hin zu fortgeschrittenen, mit echten Codebeispielen in Kotlin. Sie erfahren, wann Sie LocalContext.current verwenden, wie Sie Speicherlecks vermeiden und welche Praktiken im Jahr 2025 als „Best Practices“ gelten.
1. Der einfachste Weg: LocalContext.current
\nWenn Sie Context innerhalb einer komposablen Funktion benötigen, ist der direkteste Weg die Verwendung von LocalContext.current. Dies ist ein composable-lokal, das den aktuellen Context bereitstellt (normalerweise eine Activity oder ein ContextWrapper).
@Composable\nfun MyScreen() {\n val context = LocalContext.current\n \n Button(onClick = {\n Toast.makeText(context, "Hallo aus Compose!", Toast.LENGTH_SHORT).show()\n }) {\n Text("Toast anzeigen")\n }\n}\n\nDieser Code funktioniert, aber es gibt eine Nuance: LocalContext.current gibt Ihnen einen Context, der an das aktuelle CompositionLocal gebunden ist. In den meisten Fällen ist das genau das, was Sie brauchen. Denken Sie jedoch daran, dass ein solcher Context nicht an eine ViewModel übergeben oder in langlebigen Objekten gespeichert werden sollte – dies kann zu Speicherlecks führen.
Wann sollte man dies verwenden?
\n- \n
- Für einmalige Aktionen in der UI: Toast, Snackbar, Activity starten. \n
- Für den Zugriff auf Ressourcen:
context.getString(R.string.app_name). \n - Für die Arbeit mit Systemdiensten:
context.getSystemService(). \n
2. Context in ViewModel: Der richtige Ansatz
\nEiner der häufigsten Fehler ist es, Context direkt an eine ViewModel zu übergeben. In Android Architecture Components gilt dies als Antipattern, da die ViewModel die Activity überleben kann und der Context veraltet wird. Verwenden Sie stattdessen AndroidViewModel.
class MyViewModel(application: Application) : AndroidViewModel(application) {\n \n private val context = getApplication<Application>().applicationContext\n \n fun loadData() {\n // Verwenden Sie applicationContext, der sicher ist\n val prefs = context.getSharedPreferences("my_prefs", Context.MODE_PRIVATE)\n }\n}\n\nIn Compose können Sie eine Instanz einer solchen ViewModel auf standardmäßige Weise erhalten:
\n\n@Composable\nfun MyScreen() {\n val viewModel: MyViewModel = viewModel()\n // Context ist bereits innerhalb der ViewModel, muss nicht aus der UI übergeben werden\n}\n\nVorteil: applicationContext lebt, solange der Prozess lebt, und ist unabhängig vom Lebenszyklus der Activity. Dies ist sicher und wird von Google empfohlen.
3. Context in CompositionLocal: Benutzerdefinierte Provider
\nManchmal müssen Sie einen spezifischen Context übergeben (z. B. für Tests oder für ein Modul mit einer Bibliothek). In solchen Fällen können Sie Ihr eigenes CompositionLocal erstellen.
val LocalCustomContext = staticCompositionLocalOf<Context> {\n error("No custom context provided")\n}\n\n@Composable\nfun CustomContextProvider(context: Context, content: @Composable () -> Unit) {\n CompositionLocalProvider(LocalCustomContext provides context) {\n content()\n }\n}\n\n// Verwendung:\n@Composable\nfun MyScreen() {\n val customContext = LocalCus