measure() may not be called multiple times on the same Measurable
I am creating an app that uses Flickr api to fetch images page by page using Pager 3 library and show it on the screen using Jetpack Compose. All works fine until it will load 4-5 pages (looks like it is floating).
I receive an error:
Process: com.peterstaranchuk.flickrclient, PID: 9843
java.lang.IllegalStateException: measure() may not be called multiple times on the same Measurable
at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:86)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.kt:1236)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release$default(LayoutNode.kt:1232)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-0kLqBqw(MeasureAndLayoutDelegate.kt:171)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.access$doRemeasure-0kLqBqw(MeasureAndLayoutDelegate.kt:38)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:207)
at androidx.compose.ui.platform.AndroidComposeView.onMeasure(AndroidComposeView.android.kt:547)
at android.view.View.measure(View.java:17430)
it not points to some place on my code and it's looks like it is related with the Jetpack compose measurement.
I checked all available info and didn't find an answer. May be someone has the same problem? Would be very appreciate for any clue.
My view model:
class SearchViewModel(
private val interactor: SearchInteractor,
private val photosPresentationMapper: PhotoPresentationMapper,
eventSender: ScreenEventSender<SearchContract.Event>,
dispatchers: DispatchersProvider
) : BaseViewModel<SearchContract.Event>(eventSender, dispatchers) {
fun observePhotos(): Flow<PagingData<PhotoPresentation>> {
return interactor.getPagedPhotos("nature")
.flowOn(dispatchers.io)
.catch { /*todo handle error state */
Log.d("", it.message.toString())
}
.map {
it.map {
photosPresentationMapper.map(it)
}
}
}
}
Screen composable:
@Composable
fun ScreenContent() {
val lazyPhotoItems: LazyPagingItems<PhotoPresentation> = vm.observePhotos().collectAsLazyPagingItems()
Column {
Box(
modifier = Modifier
.wrapContentSize(Alignment.Center)
.background(Color(ContextCompat.getColor(LocalContext.current, R.color.black60transparency)))
.padding(8.dp)
) {
Row(
modifier = Modifier
.wrapContentSize()
.fillMaxWidth()
.clip(RoundedCornerShape(50))
.background(colorResource(id = R.color.search_field_background_color)),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Icon(
painterResource(id = R.drawable.ic_search_image),
contentDescription = stringResource(R.string.search_screen_magnifier_icon_content_description),
tint = Color.White
)
Text(
modifier = Modifier.padding(top = 8.dp, bottom = 8.dp, start = 4.dp),
text = stringResource(R.string.search_screen_search_field_text),
fontSize = 12.sp,
color = colorResource(id = R.color.search_field_text_color),
fontFamily = getFont(R.font.nunito_sans_extra_bold)
)
}
}
LazyColumn (content = {
items(lazyPhotoItems.itemCount, {
lazyPhotoItems[it]!!.id
}) { index ->
ImageItem(lazyPhotoItems[index]!!)
}
}, modifier = Modifier.fillMaxSize())
}
}
I use:
//paging
implementation "androidx.paging:paging-runtime:$paging_version"
implementation "androidx.paging:paging-compose:$paging_compose_version"
with the versions:
compose_version = '1.0.1'
paging_compose_version = "1.0.0-alpha12"
I recommend you to add .cachedIn(viewModelScope)
Look at comment // Here
fun observePhotos(): Flow<PagingData<PhotoPresentation>> {
return interactor.getPagedPhotos("nature")
.cachedIn(viewModelScope) // Here
.flowOn(dispatchers.io)
.catch { /*todo handle error state */
Log.d("", it.message.toString())
}
.map {
it.map {
photosPresentationMapper.map(it)
}
}
}
I had exactly the same error and it seems like it is related with this bug.
So fix was just to update jetpack compose to 1.1.0-rc01
version