Question Details

No question body available.

Tags

android kotlin android-jetpack-compose kotlin-coroutines

Answers (2)

Accepted Answer Available
Accepted Answer
May 6, 2026 Score: 3 Rep: 22,539 Quality: Expert Completeness: 80%

GlobalScope is indeed the culprit here. It uses the Default dispatcher under the hood, but everything UI related must run on the Main dispatcher.

The reason for that is that the entire UI is single-threaded (albeit massively asynchronous) to guarantee that no race conditions can occur: One thread changing some state while another thread reads that state at the same time. This thread is usually the main thread, the only thread that the Main dispatcher provides.

In your case that means that listState.scrollToItem(it) must be moved to the Main dispatcher. You could do that by simply passing it as a parameter to launch:

GlobalScope.launch(Dispatchers.Main) { listState.scrollToItem(50) //
May 6, 2026 Score: 1 Rep: 177 Quality: Low Completeness: 60%

The best way to solve this is to have your Player update a piece of state (like currentPlayingIndex), and then have a LaunchedEffect watch that index. When the index changes, the effect triggers the scroll. This avoids the "measure layout" crash because LaunchedEffect runs safely outside the immediate measure/layout pass.

@Composable
fun MyMusicList(player: Player) {
    // 1. Properly remember the list state
    val listState = rememberLazyListState()

// 2. Create a scope for manual interactions (if needed) val scope = rememberCoroutineScope()

// 3. Track the current index in a way Compose can see // In a real app, this might come from your ViewModel var currentTrackIndex by remember { mutableStateOf(0) }

// 4. Attach the listener safely DisposableEffect(player) { val listener = object : Player.Listener { override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) { currentTrackIndex = player.currentMediaItemIndex } } player.addListener(listener) onDispose { player.removeListener(listener) } }

// 5. THE FIX: Watch for index changes and scroll LaunchedEffect(currentTrackIndex) { // This block runs every time currentTrackIndex changes // It's safe, lifecycle-aware, and won't cause the "measure" crash listState.animateScrollToItem(currentTrackIndex) }

LazyColumn(state = listState) { // ... your items } }