Search code examples
android-jetpack-composeandroid-jetpack-navigation

NullPointerException at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList


I have a Drawer on my MainScreen which navigates me through drawer screens, but for some reason when I try to navigate to two specific screens (this only happens at the first time when I open the app), my app crashes with this error:

FATAL EXCEPTION: main
                                                                                                    Process: com.tags.taglife, PID: 21478
                                                                                                    java.lang.NullPointerException                                                                      at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:245)                                                                                       at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:760)                                                                                          at android.view.View.draw(View.java:24398)                                                                                                  at android.view.View.updateDisplayListIfDirty(View.java:23256)                                                                                          at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4732)                                                                                             at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4704)                                                                                           at android.view.View.updateDisplayListIfDirty(View.java:23203)                                                                      at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4732)                                                                             at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4704)                               at android.view.View.updateDisplayListIfDirty(View.java:23203)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4732)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4704)
at android.view.View.updateDisplayListIfDirty(View.java:23203)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4732)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4704)
at android.view.View.updateDisplayListIfDirty(View.java:23203)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:753)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:759)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:857)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:5501)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:5194)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:4356)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2991)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:10665)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1301)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1309)
at android.view.Choreographer.doCallbacks(Choreographer.java:923)
at android.view.Choreographer.doFrame(Choreographer.java:852)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1283)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8741)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)

This is the code for one of those screens:

package com.tags.taglife.presentation.MainScreen.sidebar

import android.annotation.SuppressLint
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import com.tags.taglife.presentation.MainScreen.MainViewModel
import com.tags.taglife.presentation.MainScreen.NavScreens
import com.tags.taglife.presentation.ProgressScreen
import com.tags.taglife.presentation.tutorial.ItemModel
import com.tags.taglife.presentation.tutorial.TutorialViewModel
import com.tags.taglife.ui.theme.bottomLine
import com.tags.taglife.ui.theme.white
import taglife.R

@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun Tutorial(
    modifier: Modifier = Modifier,
    viewModel: MainViewModel,
    tutorialViewModel: TutorialViewModel = hiltViewModel()
) {
    viewModel.setCurrentScreen(NavScreens.DrawerScreens.Tutorial)
    val isDark = tutorialViewModel.isDarkTheme
    val loading = tutorialViewModel.isLoaded

    if (!loading.value)
        ProgressScreen()
    else {
        Column(
            modifier = modifier
                .fillMaxWidth()
                .verticalScroll(rememberScrollState())
                .padding(20.dp),
        ) {
            //INSTRUCTIONS FOR USE
            Title(R.string.instructions_for_use)
            tutorialViewModel.instructions.mapIndexed { index, item ->
                Item(isDark = isDark.value, item = item, index = index + 1)
            }
            Spacer(modifier = Modifier.height(15.dp))
            //FUNCTIONS
            Title(text = R.string.functions_of_homepage_buttons)
            tutorialViewModel.functions.mapIndexed { index, item ->
                Item(isDark = isDark.value, item = item, index = index + 1)
            }
            Spacer(modifier = Modifier.height(15.dp))

            //QR CODE
            Title(text = R.string.qr_code_functions)
            tutorialViewModel.qrCodeFunctions.mapIndexed { index, item ->
                Item(isDark = isDark.value, item = item, index = index + 1)
            }
            Spacer(modifier = Modifier.height(15.dp))

            //NON NFC SCAN TAG
            Title(text = R.string.non_nfc_scan_tag)
            tutorialViewModel.nonNFCScanTag.mapIndexed { index, item ->
                Item(isDark = isDark.value, item = item, index = index + 1)
            }
        }
    }
}

@Composable
fun Title(text: Int) {
    Text(
        text = stringResource(id = text),
        fontWeight = FontWeight.Bold,
        fontSize = 20.sp,
        color = MaterialTheme.colors.primary,
    )
}

@Composable
fun Item(
    isDark : Boolean,
    item: List<ItemModel>,
    index: Int
) {
    val myId = index.toString()
    var image: Int = R.drawable.vector
    var mainText = buildAnnotatedString {
        append("$index. ")
        item.forEach {
            if (it.text != null)
                append(stringResource(id = it.text!!))
            if (it.icon != null) {
                image = it.icon!!
                appendInlineContent(myId, "[icon]")
            }
        }
    }

    val inlineContent = mapOf(
        Pair(
            myId,
            InlineTextContent(
                Placeholder(
                    width = 30.sp,
                    height = 30.sp,
                    placeholderVerticalAlign = PlaceholderVerticalAlign.TextCenter
                )
            ) {
                Image(
                    painter =  painterResource(image),
                    modifier = Modifier.padding(5.dp),
                    contentDescription = "",
                    colorFilter = if (isDark) ColorFilter.tint(white) else null
                )
            }
        )
    )


    Column(
        modifier = Modifier
            .fillMaxWidth(), verticalArrangement = Arrangement.Center
    ) {

        Text(
            text = mainText,
            inlineContent = inlineContent,
            textAlign = TextAlign.Start,
            modifier = Modifier
                .fillMaxWidth()
                .padding(vertical = 12.dp)
        )
        Spacer(
            modifier = Modifier
                .height(1.dp)
                .fillMaxWidth()
                .background(bottomLine)
        )
    }
}

I tried simply to navigate to those screens via drawer.


Solution

  • I figured it out. I needed to update my whole project to a new jetpack compose version, and compileSdk to 33.