При проверке приложения с целью улучшения скорости прокрутки списка я обнаружил, что изображения и иконки постоянно перекомпонуются, даже если их состояние не изменяется! Довольно странно, не правда ли? Например…
var counter: Int by remember { mutableStateOf(0) } Column(modifier = Modifier.fillMaxSize()) { Image( painter = painterResource(id = R.drawable.ic_launcher_background), contentDescription = null ) Text(text = "Text1") // text1 Button(onClick = { counter += 1 }) { Text(text = "Click me ") } Text("I've been clicked $counter times") }
Когда counter
меняется, Text1
пропускается, а Image
все время перекомпонуется.
По всей видимости, проблема заключается в том, что Painter
не считается stable типом. Это означает, что компилятор не может надежно определить, изменился ли объект, в результате чего приходится постоянно перекомпоновывать Image
.
Посмотрите “Объяснение Стабильность в Jetpack Compose” от Бена Тренгроува.
Решение
Для векторных ресурсов мы можем использовать ImageVector
вместо Painter
, поскольку ImageVector считается стабильным типом, так как он помечен как @Immutable.
// From resources Image( imageVector = ImageVector.vectorResource(id = R.drawable.ic_launcher_background), ... ) // For material icons Image( imageVector = Icons.Default.ArrowForward, ... )
Для растровых изображений можно создать компонент-обертку, принимающий drawableResId
вместо painter
…
@Composable fun GetcontactImage( drawableResId: Int, modifier: Modifier = Modifier, ... ) { val painter = painterResource(id = drawableResId) Image( painter = painter, contentDescription = "", modifier = modifier ) }
Поскольку GetcontactImage
(или Icon) принимает стабильные параметры (drawableResId: Int), то считается, что его можно пропустить, если его параметры не изменились.
Примечание: При разработке многократно используемых компонентов лучше передавать в качестве param типы drawableResId/color, а не Painter
. Обратитесь к документации по Android.