Kotlin, Android Studio 中的 Uri null 错误:java.io.FileNotFoundException: No content provider: {null}

问题描述 投票:0回答:2

我正在使用 Jetpack Compose 在 Android Studio 中创建一个应用程序。在主屏幕中,我有一个按钮,当它被点击时,它会通过

registerForActivityResult(ActivityResultContracts.PickVisualMedia())
打开图库,然后当图像被选中时,它会导航到显示图像的另一个屏幕,然后用 MlKit vision 进行分析。这是主要活动

private val selectMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()){ uri ->
        if (uri != null){
            val encodedUri = Uri.encode(
                uri
                    .toString()
                    .replace('%', '|')
            )
        }
    }


    @ExperimentalPermissionsApi
    @ExperimentalCoroutinesApi
    @ExperimentalCoilApi
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val navController = rememberNavController()
            AppNavigation(navController = navController, selectMedia, encodedUri)
        }

这是主屏幕,当单击按钮时,画廊将启动,并使用 LaunchedEffect 导航到另一个屏幕

ox(
                        Modifier
                            .weight(1f)
                            .clickable {
                                selectMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
                            }, contentAlignment = Alignment.Center) {
                        Column(horizontalAlignment = Alignment.CenterHorizontally) {
                            val gallery =
                                painterResource(id = R.drawable.icons8_im_genes_de_carpetas_32__1_)
                            Image(
                                painter = gallery,
                                contentDescription = null,
                                modifier = Modifier.size(36.dp, 36.dp)
                            )
                            Text(text = "Imágenes", fontFamily = Inter, fontSize = 12.sp)
                        }
                    }
                    LaunchedEffect(key1 = selectMedia){
                        navController.popBackStack()
                        navController.navigate(AppScreens.SecondScreenImage.route + "/{$encodedUri}")
                    }

这是接收uri的文件

val imageUri = textUri?.toUri()

    val textChanged = mutableStateOf("")
    val recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)

    val image = InputImage.fromFilePath(context, imageUri!!)
    recognizer.process(image)
        .addOnSuccessListener {
            textChanged.value = it.text
        }
        .addOnFailureListener {
            Log.e("TEXT_REC", it.message.toString())
        }

我需要对 Uri 进行编码以便通过 navController 发送它,但我认为我遇到的问题是 encodedUri 常量为空或至少为空字符串,当它到达最终屏幕时,它是转向 Uri,它没有要转换的内容,因为我得到的错误出现在图像常量的最后一个屏幕中。 我能做什么?当 encodedUri 常量在 MainActivity 中并且在常量中它没有范围时,我如何访问它?

android nullpointerexception android-jetpack-compose
2个回答
0
投票

这里的主要问题是你的

LaunchedEffect
。您正在使用
selectMedia
作为键 - 这是错误的。启动效果会在第一次合成时运行,然后在其键更改时运行。在您的情况下,密钥永远不会改变。您需要做的是将您的 LaunchedEffect 基于 uri:

LaunchedEffect(encodedUri) {
    if (encodedUri != null) {
        // navigate
    }
}

在你的活动中,

encodedUri
必须是
State
,或者其他一些可观察的对象:

var encodedUri by mutableStateOf<String?>(null)

如果您不需要在 Activity 中定义启动器,最好将其完全移动到组合中:

@Composable
fun Screen() {
    val selectMedia = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.PickVisualMedia(),
    ){ uri ->
        // parse uri and navigate from here
        val encodedUri = ...
        navController.navigate(...)
    }

    Button(onClick = { selectMedia.launch(...) }) {}
}

0
投票

那是因为您没有更新值并且没有将其传递给 App Navigation 可组合项,您应该使编码的 uri 可变状态,以修复将以下内容添加到您的主要 Activity 也通过提升状态(提升在 MainActivity 中启动状态):

val encodedUri = remember { mutableStateOf<String?>(null) }

更新 slecetMedia 值:

private val selectMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
    if (uri != null) {
        encodedUri.value = Uri.encode(
            uri
                .toString()
                .replace('%', '|')
        )
    }
}

然后将 encodedUri 的状态传递给 AppNavigation 可组合项:

 AppNavigation(navController = navController, selectMedia, encodedUri)

更新 launchedEffect 以处理空值,如果编码状态值不为空,它将导航,如果为空,则不会导航:

LaunchedEffect(key1 = selectMedia) {
    if (encodedUri != null) {
        navController.popBackStack()
        navController.navigate(AppScreens.SecondScreenImage.route + "/{$encodedUri}")
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.