Site icon AppTractor

Уменьшаем рекомпозиции для изображений в Jetpack Compose

При проверке приложения с целью улучшения скорости прокрутки списка я обнаружил, что изображения и иконки постоянно перекомпонуются, даже если их состояние не изменяется! Довольно странно, не правда ли? Например…

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.

Exit mobile version