#android #android-jetpack-compose
Вопрос:
У меня есть экран, на котором отображается LazyVerticalGrid с изображениями и верхняя панель с OnClick, которая создает новое действие для результата, чтобы выбрать каталог для отображения изображений
@ExperimentalFoundationApi @Composable fun DisplayPictures( pictures: Listlt;Urigt;, navController: NavController, appBarName: String = stringResource(id = R.string.choose_folder), onNewDirectoryUri: (uri: Uri?) -gt; Unit = { } ) { var showDirectorySelect by remember { mutableStateOf(false) } if (showDirectorySelect) { val launcher = rememberLauncherForActivityResult( ActivityResultContracts.OpenDocumentTree(), onResult = { onNewDirectoryUri(it) showDirectorySelect = false }) LaunchedEffect(key1 = Unit) { launcher.launch(null) } } Scaffold(topBar = { TopAppBar(title = { Text( text = appBarName.dropLastWhile { predicate -gt; predicate == '%' }, Modifier.padding(8.dp) ) }, Modifier.clickable { showDirectorySelect = true }) }) { if (!showDirectorySelect) { LazyVerticalGrid( maxColumnWidth = 150.dp, paddingDp = 4.dp, pictures = pictures ) { uri -gt; val route = Screen.Detail.createRoute( URLEncoder.encode( uri.toString(), "UTF-8" ) ) //Prevent multi-clicking and multi-touch if (!navController.currentDestination?.route?.contains("detail")!!) { navController.navigate(route) } } } } }
Но по какой-то причине мое приложение вылетает с исключением TransactionTooLargeException после того, как пользователь выбрал каталог или просто закрыл приложение в фоновом режиме(например, нажал кнопку «Домой»). Я предполагаю, что проблема в LazyVerticalGrid(его еще одна составная функция, которая представляет собой просто ленивый столбец со строками), который содержит изображения. Таким образом, изображение является составной функцией, которая загружает изображение из URI
//A wrapper around Image that shows placeholder and loading image via URI @ExperimentalFoundationApi @Composable fun Picture( uri: Uri, modifier: Modifier, size: Size, onClick: () -gt; Unit = {}, ) { val bitmap: MutableStatelt;Bitmap?gt; = rememberSaveable { mutableStateOf(null) } //Coil and other libraries that can get image from uri get context this way val context = LocalContext.current bitmap.value ?: run { LaunchedEffect(Unit) { launch(Dispatchers.IO) { try { bitmap.value = context.contentResolver.loadThumbnail(uri, size, null) } catch (e: Exception) { } } } } Box( modifier = modifier .aspectRatio(1f) .placeholder(visible = bitmap.value == null) ) { bitmap.value?.let { Log.i("longgg",uri.toString()) Image( bitmap = it.asImageBitmap(), contentDescription = null, contentScale = ContentScale.Crop, modifier = Modifier .clip(RectangleShape) .fillMaxSize() .clickable { onClick() } ) } }
По мере того, как я исследовал всю функцию создания, DisplayPictures перекомпозирует и LazyGrid загружает все изображения снова после завершения ActivityResultContract. Это приводит к загрузке большого количества миниатюр, и я получаю исключение TransactionTooLargeException. onNewDirectoryUri создает новое событие mvi, которое запускает изображения, но с новыми параметрами(новые изображения и т. Д.). Как я могу исправить это поведение?
Я узнал, что метод loadThumbnail создает пакет под капотом
final Bundle opts = new Bundle(); opts.putParcelable(EXTRA_SIZE, new Point(size.getWidth(), size.getHeight()));
Ответ №1:
Исключение TransactionTooLargeException возникает, когда данные, передаваемые между двумя действиями, слишком велики, я думаю, что пакет имеет ограничения на объем данных, которые он может переносить. Проверьте, какой результат вы отправляете через пакеты.
Старайтесь избегать отправки растровых изображений, вместо этого просто отправьте URL-адрес изображения и перезагрузите его в своей активности.
Комментарии:
1. Единственное, что я передаю через пакет, — это URI выбранного пользователем каталога. Я передаю только URI изображению, оно получает миниатюру(растровое изображение) внутри функции
2. Затем проверьте, сколько раз этот выбор Uri прерывается, если он прерывается в 3-4 Uri, то, безусловно, в пакете есть некоторые данные, которые вызывают этот сбой.