2

I am writing a LazyColumn, items are LazyRows.

But the PasserItem keeps recomposing when gently swipe, I see log keep pringing and never stop.

I come here for help.

  1. Why this happen, any state wrong?
  2. I find tow ways stop it. remove items in MemoList2, or remove AnimatedVisibility in PasserItem2. Why these ways help?
  3. Is my pattern implementing get-in animation with AnimatedVisibility proper?(I want anim run only once)
data class Passer(val username: String?, val memo: Array<String>)

MainActivity#onCreate

val live = MutableLiveData<Array<Passer>>()
live.value = Array(100) {
    Passer("$it", arrayOf("$it", "$it"))
}
setContent {
    PasserTheme {
        Home2(live)
    }
}
private const val TAG = "Home"

@Composable
fun Home2(passersLive: LiveData<Array<Passer>>) {
    val passers = passersLive.observeAsState(initial = arrayOf())
    Scaffold {
        Box(
            modifier = Modifier.fillMaxSize(),
            content = { PasserList2(passers = passers.value) }
        )
    }
}

@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun PasserList2(passers: Array<Passer>) {
    Log.d(TAG, "PasserList")
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        Log.d(TAG, "LazyColumn ${passers.size}")
        items(passers.size) { index ->
            PasserItem2(passer = passers[index])
            if (index != passers.size - 1) {
                Spacer(modifier = Modifier.height(32.dp))
            }
        }
    }
}

@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun PasserItem2(passer: Passer) {
    Log.d(TAG, "PasserItem ${passer.username}")
    var visibility by remember { mutableStateOf(false) }
    LaunchedEffect(key1 = visibility) {
        Log.d(TAG, "PasserItem LaunchedEffect")
        visibility = true
    }
    Log.d(TAG, "PasserItem visible $visibility")
    AnimatedVisibility(visible = visibility) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .background(MaterialTheme.colors.onBackground.copy(alpha = 0.1F))
                .padding(16.dp)
        ) {
            MemoList2(passer.memo)
        }
    }
}

@Composable
private fun MemoList2(memo: Array<String>) {
    Log.d(TAG, "MemoList")
    LazyRow(modifier = Modifier.fillMaxWidth()) {
        items(memo.size) { }
    }
}
buildscript {
    ext {
        compose_version = '1.2.0-alpha07'
        my_dependency = [:]
        my_dependency.gradle = "com.android.tools.build:gradle:7.0.4"
        my_dependency.kotlin_gradle = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"

        my_dependency.core_ktx = "androidx.core:core-ktx:1.7.0"
        my_dependency.compose_ui_ui = "androidx.compose.ui:ui:1.2.0-alpha07"
        my_dependency.compose_material = "androidx.compose.material:material:1.1.1"
        my_dependency.compose_ui_tooling_preview = "androidx.compose.ui:ui-tooling-preview:1.1.1"
        my_dependency.compose_activity = "androidx.activity:activity-compose:1.4.0"
        my_dependency.compose_runtime_livedata = "androidx.compose.runtime:runtime-livedata:1.1.1"
        my_dependency.compose_ui_tooling = "androidx.compose.ui:ui-tooling:1.1.1"

        versions = [:]
        versions.versionCode = 1
        versions.versionName = "1.0"
        versions.compileSdkVersion = 31
        versions.buildToolsVersion = '33.0.1'
        versions.minSdk = 30
        versions.targetSdk = 31
    }
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "$my_dependency.gradle"
        classpath "$my_dependency.kotlin_gradle"
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdk 31

    defaultConfig {
        applicationId "ycr.pass"
        minSdk versions.minSdk
        targetSdk versions.targetSdk
        versionCode versions.versionCode
        versionName versions.versionName
        vectorDrawables {
            useSupportLibrary true
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = '11'
        useIR = true
    }
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion compose_version
    }
    packagingOptions {
        resources {
            excludes += '/META-INF/{AL2.0,LGPL2.1}'
        }
    }
}

dependencies {

    implementation my_dependency.core_ktx
    implementation my_dependency.compose_ui_ui
    implementation my_dependency.compose_material
    implementation my_dependency.compose_ui_tooling_preview
    implementation my_dependency.compose_activity
    implementation my_dependency.compose_runtime_livedata
    debugImplementation my_dependency.compose_ui_tooling
}
Yan CR
  • 21
  • 6
  • This is the expected behavior. Any view in which animation is running will recompose for each animation frame. But `MemoList2` shouldn't be recomposed that often, unless the list changes. Why does this bother you? – Phil Dukhov Apr 10 '22 at 03:33
  • Not animation recomposing.(actually while doing anim, it does not recompose) It is when I swipe LazyColumn gentely, some of PasserItem keeps recomposing, and will never stop after the swipe is stopped. – Yan CR Apr 11 '22 at 02:04
  • During `LazyColumn` the item which wasn't on the screen and show appear is being recomposed. Without `AnimatedVisibility` you're triggering one more recomposition with `LaunchedEffect`, so it's expected that each cell will be recomposed two times. Also you have this logic `items(passers.value.size * 2)` which makes your logs kind of confusing, as you see double logs for the same index, but for different cells. Other than that there should be no extra recompositions. – Phil Dukhov Apr 11 '22 at 03:08
  • If you still have doubts, please reduce your example to [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Phil Dukhov Apr 11 '22 at 03:09
  • I improve the question. The size and double logs are not the key. I swipe and let go, then logs keep printing and will never stop. – Yan CR Apr 11 '22 at 07:27
  • I wasn't being able to reproduce it. I see a lot of `MemoList` logs, but it stops as soon as I stop scrolling, maximum amount of logs is around 30. Can you reproduce it on API 31/32 emulator? – Phil Dukhov Apr 11 '22 at 10:28
  • I use exactly the same code, and in AVD google api 31, x86_64 image. Swipe up to down gently, and it happens, Besides, i add my gradle code above – Yan CR Apr 15 '22 at 07:28
  • I downgrade my compose version to 1.1.1, and it is OK... Maybe the alpha version is not stable somewhere. But 1.1.1 has other problem, I am not able to compile the whole project using 1.1.1, then I upgrade to alpha version.. – Yan CR Apr 15 '22 at 07:33
  • If you can create an example project in which you can reproduce the problem, it is better to [report it](https://issuetracker.google.com/issues/new?component=612128) to the maintainers so that the problem can be solved before the release. – Phil Dukhov Apr 17 '22 at 06:39

0 Answers0