Android 16 Release & Google Play Anforderungen
- Stable Release: 10. Juni 2025 (Pixel-Geräte zuerst, andere Hersteller später)
- Material 3 Expressive UI: Rollout Q4 2025
- Neue Apps / Updates Pflicht: Target SDK ≥ Android 15 (API Level 35) ab 31. August
2025
- Bestehende Apps Pflicht: Target SDK ≥ Android 14 (API Level 34) ab 31. August 2025
(Verlängerung bis 1. Nov 2025 möglich)
- Android 16 Target SDK Pflicht?: Noch keine Deadline, lohnt sich aber jetzt schon
vorzubereiten
Wichtige Neuerungen in Android 16
- Adaptive Apps für große Bildschirme: Apps können nun auf allen Bildschirmen, inkl.
Tablets und Foldables, den gesamten Platz nutzen.
- Predictive Back: Systemweite Animationen für Back-Navigation und
Drei-Tasten-Navigation.
- Fortschrittsbenachrichtigungen: Live Updates für Fahrdienste, Lieferungen oder
Navigation.
- Erweiterte grafische Effekte (AGSL): RuntimeColorFilter & RuntimeXfermode für
komplexe Effekte.
- JobScheduler-Updates & ART-Optimierungen: Verbesserung der Startzeiten, System-Boot
und Kamera, ART-Performance.
- Datenschutz & Sicherheit: Verbesserter Intent-Schutz, Privacy Sandbox Integration,
sichere Standortdaten während Device Pairing.
Abbildung 1: Design Mobile Only vs Design Adaptive Apps
Praxis: Orientation Change & State-Management auf Android 16
Hier kommen praxisnahe Codebeispiele (Kotlin + Jetpack Compose) rund um Orientation
Change, State-Handling und Migration auf modernes Android (Android 16/targetSdk neuester
Stand).
Manifest: Orientation kein Config Change mehr
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:screenOrientation="unspecified"
android:configChanges="keyboardHidden|keyboard|screenLayout|uiMode">
</activity>
Hinweis: Orientation sollte nicht mehr pauschal über configChanges
abgefangen werden, um unnötige Activity Reloads zu vermeiden.
ViewModel + SavedStateHandle
@HiltViewModel
class AppViewModel @Inject constructor(
private val savedState: SavedStateHandle,
private val repo: ItemsRepository
) : ViewModel() {
private val _query = MutableStateFlow(savedState.get("query") ?: "")
val query: StateFlow = _query.asStateFlow()
val items = query
.debounce(250)
.flatMapLatest { q -> repo.search(q) }
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
fun onQueryChange(newValue: String) {
_query.value = newValue
savedState["query"] = newValue
}
}
Hinweis: SavedStateHandle ist hier optional, aber nützlich, falls App-Werte beim
Prozess-Tod erhalten bleiben sollen.
Compose-Screen: collectAsStateWithLifecycle vs. rememberSaveable
@Composable
fun SearchScreen(viewModel: AppViewModel = hiltViewModel()) {
val query by viewModel.query.collectAsStateWithLifecycle()
val items by viewModel.items.collectAsStateWithLifecycle()
Column(Modifier.fillMaxSize().padding(16.dp)) {
OutlinedTextField(
value = query,
onValueChange = viewModel::onQueryChange,
label = { Text("Suche") },
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(12.dp))
LazyColumn(Modifier.fillMaxSize()) {
items(items) { item ->
Text(item.title, Modifier.padding(vertical = 8.dp))
Divider()
}
}
}
}
Hinweis: collectAsStateWithLifecycle
ist der Standard, um Änderungen aus dem
ViewModel
automatisch zu beobachten. UI-eigener State, der unabhängig vom ViewModel ist, sollte
mit rememberSaveable
verwaltet werden.
Window-Size-Classes & Foldables
// Implementierung erforderlich, APIs teilweise noch Alpha
val windowSizeClass = calculateWindowSizeClass(this)
AppRoot(windowSizeClass.widthSizeClass)
Hinweis: Eine Methode zur Berechnung der SizeClass muss implementiert werden.
Verschiedene APIs existieren, manche noch im Alpha-Stadium.
Lifecycle & Daten sichern
@Composable
fun LifecycleAwareScreen(onStopSaveDraft: (String) -> Unit) {
var draft by rememberSaveable { mutableStateOf("") }
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner, draft) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_STOP) onStopSaveDraft(draft)
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
}
OutlinedTextField(
value = draft,
onValueChange = { draft = it },
label = { Text("Notiz") },
modifier = Modifier.fillMaxWidth()
)
}
Hinweis: Sinnvoll, wenn Eingaben vor Activity-Destroy persistiert werden sollen, z.B. in
Datenbank oder via Netzwerk.
Permissions & Privacy
- Android 13+:
POST_NOTIFICATIONS
- Android 14+: granularer Zugriff auf Media (nur ausgewählte Dateien)
- Android 16: Änderungen hier bisher minimal, relevant für Migration über mehrere
Versionen
val permission = Manifest.permission.POST_NOTIFICATIONS
val state = rememberPermissionState(permission)
LaunchedEffect(Unit) { if (!state.status.isGranted) state.launchPermissionRequest() }
Performance-Tuning
- Baseline Profiles für schnelleres Starten (Dokumentation beachten, nicht die zuvor
gezeigten Kommentare)
- R8/ProGuard sauber konfigurieren
- Immutable State + Diffing in Compose vermeiden unnötige Re-Compositions
Testing
@Test fun state_survives_rotation() {
compose.onNodeWithText("Klicks: 0").performClick()
rotateScreen()
compose.onNodeWithText("Klicks: 1").assertExists()
}
Prüft, dass der Screen-State nach Rotation erhalten bleibt.
Migrations-Checkliste
- targetSdk & compileSdk aktualisieren
- Orientation/Resize via ViewModel + SavedStateHandle + rememberSaveable
- Window Size Class & Foldables berücksichtigen
- Runtime Permissions prüfen (Android 13/14+)
- Material 3 / Compose einsetzen
- Baseline Profiles & ProGuard optimieren
- UI- & Instrumentation-Tests für Rotation/Multi-Window
Fazit
Android 16 verlangt Updates für State-Management, Layouts und teilweise Permissions. Mit
let’s dev wird deine App modernisiert, performanter und Play Store-ready – inklusive
Orientation-Handling, Multi-Window, Foldables und Performance-Tuning.