Как правильно подписаться на событие загрузки изображение в общем списке задач для item в LazyColumun Compose
Я с сервера получаю список изображений и в своей ленте их отображаю, но проблема в том, изображения могут быть большого размера, до 5 мб и мне нужно отобразить их всё, а их может быть до 50 шт в одном item.
Я не могу использовать Coil. Сервер использует Amazon они генерируют каждый раз уникальный url.
По этому я кеширую изображения в память устройства и отображаю. Сначала я думал загрузить их всё стразу, просто вызвав функцию загрузки файла в каждом item LaunchedEffect, а коллбеком вернуть путь к изображению.
Но я получал ошибку:
java.lang.OutOfMemoryError: Failed to allocate a 16 byte allocation with 199440 free bytes and 194KB until OOM, target footprint 201326592, growth limit 201326592; giving up on allocation because <1% of heap free after GC.
Поэтому я придумал другой подход вроде задач и скачиваю изображения последовательно, это помогло мне избавиться от ошибки и зависания устройства.
Но я не знаю как правильно подписаться на обновления в своем ItemPhoto чтобы он знал, что изображение с id к примеру 1 - 100 было закешировано на диске и его можно отобразить по этому пути.
Вот мой код, он полностью демонстрирует то что не gif.
@HiltViewModel
class BigFileViewModel @Inject constructor(
val serviceApi : ServiceApi
) : ViewModel(){
private val channel = Channel<DownloadImage>()
var loadedImagesList = mutableStateOf<List<DownloadImage>?>(null)
private set
init{
CoroutineScope(Dispatchers.Default).launch {
for (operation in channel) {
CoroutineScope(Dispatchers.Default).async {
serviceApi.downloadFileLink(operation.imageLink).collect{response->
if(response is NetworkResponse.Success){
updateItem(DownloadImage(operation.itemId, response.data))
}
}
}
}
}
}
private fun updateItem(downloadImage: DownloadImage) {
loadedImagesList .value = loadedImagesList .value.orEmpty() + downloadImage
}
fun downloadPhoto(itemId : Int, url : String){
viewModelScope.launch {
channel.send(DownloadImage(itemId, url))
}
}
}
@Composable
fun BigFileList(bigFileViewModel : BigFileViewModel = hiltViewModel()){
LazyColumn(content = {
items(1){
FlowRowItem(bigFileViewModel)
}
})
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun FlowRowItem( bigFileViewModel : BigFileViewModel){
FlowRow(
modifier = Modifier
.padding(8.dp),
horizontalArrangement = Arrangement.Start
) {
for(item in 0..23){
ItemPhoto((0..10000).random(), imageList.random(), bigFileViewModel)
}
}
}
@Composable
fun ItemPhoto(itemId : Int, setLink : String, bigFileViewModel : BigFileViewModel){
val link = remember { mutableStateOf<String?>( null ) }
val updateList by bigFileViewModel.loadedImagesList
LaunchedEffect(key1 = Unit, block = {
bigFileViewModel.downloadPhoto(itemId, setLink)
})
LaunchedEffect(key1 = updateList, block = {
updateList?.forEach {item->
if(item.itemId == itemId){
link.value = item.imageLink
}
}
})
link.value?.let {url->
Image(
painter = rememberAsyncImagePainter(
url,
filterQuality = FilterQuality.None,
),
contentDescription = null,
modifier = itemModifier2,
contentScale = ContentScale.Crop
)
} ?: run {
Box(contentAlignment = Alignment.Center) {
Column(
modifier = itemModifier2,
verticalArrangement = Arrangement.spacedBy(5.dp, Alignment.Top),
horizontalAlignment = Alignment.CenterHorizontally,
) {
CircularProgressIndicator()
Text("$itemId")
}
}
}
}
