Status Update
Comments
an...@google.com <an...@google.com>
ap...@google.com <ap...@google.com> #2
1. Have you saw crash in real device or only in simulators?
2. Do you use dynamic feature for language ID?
b9...@gmail.com <b9...@gmail.com> #3
Tested on Android 12 Emulator with custom executor, but cannot repro this issue.
an...@google.com <an...@google.com> #4
-
Second crash in the description is from a real device. Experienced it myself on two different Xiaomi phones, plus lots of crashes from users in the Google Play console.
-
Dynamic features are not used in the application.
As a wild guess, I have downgraded build tools from 31.0.0 to 30.0.3, compileSdk from 31 to 30, and moved all work with Language ID to the service in a separate process (just to be sure that crash can kill secondary process instead of main). This combination is in beta for 2 days by now and I don't see any SIGSEGV crashes.
b9...@gmail.com <b9...@gmail.com> #5
Hmm, I feel the crash might be something related to separate/secondary process.
I also changed compileSdk and targetSDK to 31 but still cannot repro this issue.
an...@google.com <an...@google.com> #6
On the contrary, there was no separate process before, when crashes started.
In the new build (with the aforementioned changes) I can see SIGSEGV crash, but only one instead of dozens and it has a bit different backtrace:
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR)
liblanguage_id_jni.so (offset 0x11e000)
backtrace:
#00 pc 000000000003c7c0 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 000000000003b960 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 000000000003bb48 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 000000000003bafc /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 0000000000036c98 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 0000000000032714 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 0000000000031cac /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 0000000000057438 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/oat/arm64/base.odex (offset 0x57000)
b9...@gmail.com <b9...@gmail.com> #7
FYI, ML Kit launched a new language ID SDK in the latest release, which uses a new language ID model.
Could you try the new SDK version(17.0.0) to check if you can still repro this native crash? Thanks!
an...@google.com <an...@google.com> #8
Thank you, I'll try it and check.
da...@gmail.com <da...@gmail.com> #9
Hello. I have similar experience.
- I'm using mlkit-language 16.1.1
- I didnot meet this error until using AGP 4.2
- I can get this error since using AGP 7.0
- This error raised on Release build only(minimized by R8)
- This error raised without obfuscation.
[Deleted User] <[Deleted User]> #11
an...@google.com <an...@google.com> #12
I tried the repro steps but got a NPE when I run ./gradlew :app:pPRUA
FAILURE: Build failed with an exception.
* What went wrong:
java.lang.NullPointerException
> java.lang.NullPointerException (no error message)
Could you also check if this is reproducible on 17.0.0
or 17.0.1
? If yes, could you attach the full log that I can take a look? Thanks!
[Deleted User] <[Deleted User]> #13
Here are gradle build scan logs for each branches.
All builds were clean build, and disabled build cache.
- mlkit_agp7 :
https://scans.gradle.com/s/qrymdqfzwokbq - mlkit_agp42 :
https://scans.gradle.com/s/b6644hzfyfhaw - mlkit_agp7_r8_disable_inline_optimizer :
https://scans.gradle.com/s/c6h5hy2nxod4u
Also, I pushed to update MLKit Language Id version 17.0.1 on
And here is crash log after apply 17.0.1
You can see that BuildId
of liblanguage_id_l2c_jni.so
was changed from 859ec0ec2000a39e6ae8ed42e1704f46
to be6e59455cc10135330c93acdebfc121
10-20 03:07:24.522 24587 24628 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7acf995426 in tid 24628 (pool-3-thread-3), pid 24587 (e.myapplication)
10-20 03:07:25.190 24710 24710 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
10-20 03:07:25.190 24710 24710 F DEBUG : Build fingerprint: 'google/crosshatch/crosshatch:12/SPB5.210812.002/7671067:user/release-keys'
10-20 03:07:25.190 24710 24710 F DEBUG : Revision: 'MP1.0'
10-20 03:07:25.190 24710 24710 F DEBUG : ABI: 'arm64'
10-20 03:07:25.190 24710 24710 F DEBUG : Timestamp: 2021-10-20 03:07:24.583346246+0900
10-20 03:07:25.190 24710 24710 F DEBUG : Process uptime: 0s
10-20 03:07:25.190 24710 24710 F DEBUG : Cmdline: com.example.myapplication
10-20 03:07:25.190 24710 24710 F DEBUG : pid: 24587, tid: 24628, name: pool-3-thread-3 >>> com.example.myapplication <<<
10-20 03:07:25.190 24710 24710 F DEBUG : uid: 10240
10-20 03:07:25.190 24710 24710 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7acf995426
10-20 03:07:25.190 24710 24710 F DEBUG : x0 0000007b54da9d30 x1 0000007d9a5fe7cc x2 0000000000000000 x3 0000000000000010
10-20 03:07:25.190 24710 24710 F DEBUG : x4 0000000000000000 x5 0000007c34dbc79c x6 0000002f0000083b x7 000003c300002dd5
10-20 03:07:25.190 24710 24710 F DEBUG : x8 0000000000000001 x9 0000000000000004 x10 0000000000000010 x11 0000000000000000
10-20 03:07:25.190 24710 24710 F DEBUG : x12 0000000000000000 x13 000000000000217e x14 0000007acf9932a8 x15 000000000000217e
10-20 03:07:25.190 24710 24710 F DEBUG : x16 0000000000000000 x17 0000007d9a564c78 x18 0000007a6ef18000 x19 0000007c34dbc580
10-20 03:07:25.190 24710 24710 F DEBUG : x20 0000007ca4dc7170 x21 0000007ca4dc7800 x22 0000007ca4dc71e0 x23 0000000000000000
10-20 03:07:25.190 24710 24710 F DEBUG : x24 0000000000000018 x25 0000000000000007 x26 0000000000000006 x27 0000000000000004
10-20 03:07:25.190 24710 24710 F DEBUG : x28 0000007ca4dc7090 x29 0000007cb4da9940
10-20 03:07:25.190 24710 24710 F DEBUG : lr 0000007a770a9624 sp 0000007a6f7de9c0 pc 0000007a770a96a8 pst 0000000020000000
10-20 03:07:25.190 24710 24710 F DEBUG : backtrace:
10-20 03:07:25.190 24710 24710 F DEBUG : #00 pc 00000000000386a8 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #01 pc 00000000000388a0 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #02 pc 00000000000844a0 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #03 pc 000000000008783c /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #04 pc 0000000000035fc4 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #05 pc 0000000000034954 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #06 pc 00000000000340e8 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (Java_com_google_mlkit_nl_languageid_internal_ThickLanguageIdentifier_nativeIdentifyPossibleLanguages+108) (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.191 24710 24710 F DEBUG : #07 pc 00000000002d9a44 /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+148) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #08 pc 000000000020a700 /apex/com.android.art/lib64/libart.so (nterp_helper+5648) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #09 pc 00000000000cd0dc /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #10 pc 000000000020a044 /apex/com.android.art/lib64/libart.so (nterp_helper+3924) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #11 pc 00000000000ccfa8 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #12 pc 0000000000557cb4 /system/framework/arm64/boot-framework.oat (android.os.Binder.transact+148) (BuildId: 43a571a0ad85d6451b47016336a541ecb0eb12bb)
10-20 03:07:25.191 24710 24710 F DEBUG : #13 pc 000000000020b53c /apex/com.android.art/lib64/libart.so (nterp_helper+9292) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #14 pc 00000000000b7aba /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #15 pc 000000000020a044 /apex/com.android.art/lib64/libart.so (nterp_helper+3924) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #16 pc 00000000000a7496 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #17 pc 000000000020a044 /apex/com.android.art/lib64/libart.so (nterp_helper+3924) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #18 pc 00000000000a7360 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #19 pc 000000000020ae64 /apex/com.android.art/lib64/libart.so (nterp_helper+7540) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #20 pc 000000000009e46c /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #21 pc 000000000020ae64 /apex/com.android.art/lib64/libart.so (nterp_helper+7540) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #22 pc 00000000000d33d6 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #23 pc 000000000020ae64 /apex/com.android.art/lib64/libart.so (nterp_helper+7540) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #24 pc 000000000009df0a /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #25 pc 0000000000209124 /apex/com.android.art/lib64/libart.so (nterp_helper+52) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #26 pc 000000000009e350 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #27 pc 000000000037b9ac /apex/com.android.art/javalib/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+988) (BuildId: ab2bf4ec264efdb6c452a238be38fe624de826b8)
10-20 03:07:25.191 24710 24710 F DEBUG : #28 pc 00000000003751d4 /apex/com.android.art/javalib/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+68) (BuildId: ab2bf4ec264efdb6c452a238be38fe624de826b8)
10-20 03:07:25.191 24710 24710 F DEBUG : #29 pc 000000000020aec4 /apex/com.android.art/lib64/libart.so (nterp_helper+7636) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #30 pc 000000000009e370 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #31 pc 00000000001bf35c /apex/com.android.art/javalib/arm64/boot.oat (java.lang.Thread.run+76) (BuildId: ab2bf4ec264efdb6c452a238be38fe624de826b8)
10-20 03:07:25.191 24710 24710 F DEBUG : #32 pc 00000000002d0164 /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #33 pc 000000000031ccac /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+156) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #34 pc 00000000003cf8a0 /apex/com.android.art/lib64/libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+380) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #35 pc 0000000000460894 /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+992) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #36 pc 00000000000b1910 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+264) (BuildId: ba489d4985c0cf173209da67405662f9)
10-20 03:07:25.191 24710 24710 F DEBUG : #37 pc 00000000000513f0 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: ba489d4985c0cf173209da67405662f9)
eu...@gmail.com <eu...@gmail.com> #14
Cross-posted on R8 issue tracker.
da...@gmail.com <da...@gmail.com> #15
Hi,
Looks like we figured out the root cause in
For temporary workarounds for the existing SDKs, you need to add this rule
-keep class com.google.mlkit.nl.languageid.internal.LanguageIdentificationJni { *; }
for language-id 16.1.1
, and add this rule
-keep class com.google.mlkit.nl.languageid.internal.ThickLanguageIdentifier { *; }
for version language-id 17.0.0+
for the newer model.
We'll fix this issue in the upcoming release so that you'll not need these workarounds in the future release.
Thanks a lot for reporting this issue!
as...@gmail.com <as...@gmail.com> #16
Added workarounds in
an...@google.com <an...@google.com> #17
ba...@gmail.com <ba...@gmail.com> #18
I have found a workaround that works for me.
The LazyPagingItems.kt
file was copied from the androidx.paging:paging-compose
artifact into my project (it doesn't have any other dependencies).
I modified it to add a flag inside the LazyPagingItems
class:
/**
* The number of items which can be accessed.
*/
val itemCount: Int get() = itemSnapshotList.size
// The code below was added:
/**
* Added to fix scroll state restoration - wait for this flag to be set to true
* before setting your [LazyListState] on the [LazyColumn].
*
* @author Baptiste Candellier
*/
var hasRestoredItems: Boolean = false
private set
The flag is set inside the updateItemSnapshotList()
method
private fun updateItemSnapshotList() {
itemSnapshotList = pagingDataDiffer.snapshot()
// The code below was added:
hasRestoredItems = true
}
Then on my composable, I wait for this flag to become true to pass the "real" LazyListState
, that comes from a ViewModel
.
LazyColumn(
// Wait for the items to be restored to set the real list state, so that it isn't reset in the meantime
state = if (lazyPagingItems.hasRestoredItems) lazyListState else LazyListState()
) {
// ... your items here
There might be edge cases but it works for me, I hope it helps.
im...@gmail.com <im...@gmail.com> #19
// Save and restore list state
fun lazyListSaver(): Saver<MutableState<LazyListState>, *> = listSaver(
save = { listOf(it.value.firstVisibleItemIndex, it.value.firstVisibleItemScrollOffset) },
restore = {
mutableStateOf(LazyListState(
firstVisibleItemIndex = it[0],
firstVisibleItemScrollOffset = it[1]
))
}
)
// Usage
fun ProfileTab(lazyListState: MutableState<LazyListState>)
LazyVerticalGrid(
state = lazyListState.value,
)
}
Hope this solution works.
an...@google.com <an...@google.com> #20
rememberLazyListState() is doing pretty much the same internally. Could you please elaborate a bit more on why the build in solution doesn't work for you?
im...@gmail.com <im...@gmail.com> #21
Ouch! I'm new on Compose, so don't know how state, rememberLazyListState() works so i directly pass
fun ProfileTab() LazyVerticalGrid( state = rememberLazyListState(), ) }
and while i switch tab from 1->2 and back from 2-> the state of LazyVerticalGrid regenerated, but i didn't try to save in state on globally and pass in composable.
After i seeing this
wh...@gmail.com <wh...@gmail.com> #22
as a lot of people mentioned, LazyColumn can't restore position correct when Paging has a Header
this is because rememberLazyListState can restore position when there are at least 1 element in the list
but if there is a Header or Footer in LazyColumn, then it will restore in first frame when paging's item count is still 0
so I store listState in ViewModel and restore it when Paging item count > 0
val listState = if (pagingData.itemCount > 0) viewModel.listState else rememberLazyListState()
ro...@gmail.com <ro...@gmail.com> #23
Try this workaround, you need to check lazyPagingItems before use:
@Composable
fun MainFrame(lazyPagingItems: LazyPagingItems<PerformanceEvent.Building>) {
val refresh = lazyPagingItems.loadState.refresh
// My temp solution
if (lazyPagingItems.itemCount == 0 && refresh is LoadState.NotLoading ) return //skip dummy state, waiting next compose
LazyColumn { ... }
}
ne...@gmail.com <ne...@gmail.com> #24
Here is a workaround:
@Composable
fun <T : Any> LazyPagingItems<T>.rememberLazyListState(): LazyListState {
// After recreation, LazyPagingItems first return 0 items, then the cached items.
// This behavior/issue is resetting the LazyListState scroll position.
// Below is a workaround. More info: https://issuetracker.google.com/issues/177245496.
return when (itemCount) {
// Return a different LazyListState instance.
0 -> remember(this) { LazyListState(0, 0) }
// Return rememberLazyListState (normal case).
else -> androidx.compose.foundation.lazy.rememberLazyListState()
}
}
Should we still expect a fix from any Jetpack library ?
ke...@gmail.com <ke...@gmail.com> #25
Could you provide a version name that contains the fix?
su...@gmail.com <su...@gmail.com> #26
Only thing that works is disabling phone rotation, or creating the pager flow before the NavHost. Are there any solutions?
wh...@gmail.com <wh...@gmail.com> #27
If your project does not have a deep dependency on the paging3 library, I recommend implementing a simple paging library yourself to avoid all the weird features of paging3. Paging library needs the coordination of the view layer and the model layer. It doesn't make sense to encapsulate these together.
Here's an example from my project. If you don't need to modify the list, it can be implemented much simpler.
da...@gmail.com <da...@gmail.com> #28
al...@mercari.com <al...@mercari.com> #29
Still not fixed in latest versions, workaround works. Please consider re-opening the issue.
co...@gmail.com <co...@gmail.com> #30
jo...@kalderstam.se <jo...@kalderstam.se> #31
Seconded. Still a problem in 1.3.1
[Deleted User] <[Deleted User]> #32
In our case, it seems to be triggered by adding headers/footers to the `LazyColumn`.
Please consider re-opening the issue.
il...@google.com <il...@google.com> #33
The default case (all of your items are loaded asynchronously) was fixed in cachedIn
in your layer above Compose (e.g., your ViewModel layer).
However, the case where you have some items available immediately (like a header and footer) and some items available only asynchronously, is not fixed. This is broken whether you use Paging or not - any data loaded from a Flow
would suffer this same problem (as they also would not be available in the first composition).
Creating an generic API for informing the Lazy Layout of when all asynchronously loaded items have finished loading (particularly noting that there can be multiple items
blocks loading from multiple asynchronous sources) is not something we can solve in the short or medium term.
That being said, we believe there may be a way to solve this in the specific case of headers+footers and a single call to collectAsLazyPagingItems
without having to wait for an overhaul of either the Paging or Lazy layout APIs, so we will be reopening this issue to track that internal investigation.
bi...@gmail.com <bi...@gmail.com> #34
pa...@outlook.com <pa...@outlook.com> #35
Sounds like Paging and Component are being developed with a lot of various serious issues that are piling with each version, and the team does not have any intention of fixing them. That's alright, at least now we can finally stop waiting for this to be fixed and instead stop using them entirely. Good luck with this.
cl...@google.com <cl...@google.com> #36
Compose requires an initial state for valid first composition.
Paging 3's entire architecture is based around emitting data through a Flow that doesn't emit until collected.
Therefore, significant changes within Paging 3 are required to enable initial states in paging-compose without collection. While these changes are not easily resolvable, we hope to address them in the coming year.
au...@gmail.com <au...@gmail.com> #37
vi...@gmail.com <vi...@gmail.com> #39
ty...@gmail.com <ty...@gmail.com> #40
ap...@google.com <ap...@google.com> #41
Branch: androidx-main
commit 4a567a83c33a3f15556d4777e97327e418cbe42e
Author: Clara Fok <clarafok@google.com>
Date: Wed Apr 26 12:29:43 2023
Initialize PagingDataDiffer with cached data
PagingDataDiffer constructor now accepts a nullable PagingData containing a nullable cached PageEvent.Insert. PagePresenter and combinedLoadStatesCollection will be initialized wiht the cached data if present. This allows cached items and loadStates to be accessible immediately without requiring any collection.
Note that HintReciver and UiReceiver is not set, hence differ will not respond to any UI input (scrolling / refresh etc) until a real PagingData has been collected from.
Test: ./gradlew paging:paging-common:test
Bug: 177245496
Change-Id: I3a9a80486a1e345699745311dcb585efbf7939bd
M paging/paging-common/src/main/kotlin/androidx/paging/PagePresenter.kt
M paging/paging-common/src/main/kotlin/androidx/paging/PagingDataDiffer.kt
M paging/paging-common/src/test/kotlin/androidx/paging/PagingDataDifferTest.kt
ap...@google.com <ap...@google.com> #42
Branch: androidx-main
commit ac2a48843976a46cdf9eb6db1d4d08d59deecbd8
Author: Clara Fok <clarafok@google.com>
Date: Tue Apr 25 16:43:38 2023
Exposed cached data via PagingData
When using Flow<PagingData<T>>.cachedIn(scope), data that has been collected within that generation is cached for as long as the scope remains alive.
Normally the cachedData can only be accessed by new subscriptions when they collect on the SharedFlow returned by cachedIn. Now we expose this cachedData via PagingData so that the cached data can be accessed synchronously without requiring collection.
Test: ./gradlew paging:paging-common:test
Bug: 177245496
Change-Id: I36a894d7d90f61396604e7847c5be6027b5e0991
M paging/paging-common/src/main/kotlin/androidx/paging/CachedPageEventFlow.kt
M paging/paging-common/src/main/kotlin/androidx/paging/CachedPagingData.kt
M paging/paging-common/src/main/kotlin/androidx/paging/PagingData.kt
M paging/paging-common/src/test/kotlin/androidx/paging/CachingTest.kt
8h...@gmail.com <8h...@gmail.com> #43
ap...@google.com <ap...@google.com> #44
Branch: androidx-main
commit 75b22ef9f04fc4d615b75f65d904dd4cc765bffd
Author: Clara Fok <clarafok@google.com>
Date: Thu Apr 27 14:03:07 2023
Cached data immediately available in LazyPagingItems
Paged data can be cached via pager.flow.cachedIn(scope). If collecting LazyPagingItems from this cachedIn flow, any cached data will be made available for presentation upon #collectAsLazyPagingItems initialization without requiring asynchronous collection.
This means that upon configuration change or navigating away and back, instead of LazyPagingItems containing zero items, it will now contain previously loaded data that can be immediately presented within initial composition. This helps preserve scroll state and a smoother UI transition.
Note that this only applies to flows returned directly from pager.flow.cachedIn(scope), so mapping or transformations should be applied prior to cachedIn.
Test: ./gradlew paging:paging-compose:cC
Fixes: 177245496
Relnote: "Cached data from pager.flow.cachedIn that has been collected in LazyPagingItems will now be immediately available after state restoration without requiring asyncrhonous collection. This means the cached data will be ready for presentation immediately upon initial composition after state is restored."
Change-Id: I97a6078c0563f8017af24448c32e59b86a987465
M paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
M paging/paging-compose/src/main/java/androidx/paging/compose/LazyPagingItems.kt
cl...@google.com <cl...@google.com> #45
This has been fixed internally and will be available in the next release. The next release version is TBD.
In short, the fix works by making cached data immediately available for presentation after config change / navigation. This prevents the list from having zero items right after config change/ navigation so the scroll state will be preserved without requiring workarounds such as
That said, it only works if there is cached data to begin with. This means you need pager.flow.cachedIn(scope)
. Note that any PagedData mapping/transformations should be applied prior to cachedIn(), such as
val pager = pager.flow.map { pagingData ->
pagingData.map {
// map items
}
}.cachedIn(scope)
8h...@gmail.com <8h...@gmail.com> #46
Is it going to fix incorrect loadState
(Loading
) as well (to avoid displaying incorrect refresh indicator to users)?
val lazyPagingItems = viewModel.pagingDataExample.collectAsLazyPagingItems()
val loadState = lazyPagingItems.loadState.refresh // loadState == Loading initially on config changes/navigation
It should be NotLoading
if data is returned from cahce and no request to refresh is triggered
cl...@google.com <cl...@google.com> #47
Yes it will start with NotLoading
if displaying cachedData.
na...@google.com <na...@google.com> #48
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.paging:paging-common:3.2.0-alpha05
il...@google.com <il...@google.com> #49
I'll note that while some of the changes from this bug made it into
ju...@google.com <ju...@google.com> #50
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.paging:paging-compose:1.0.0-alpha20
so...@gmail.com <so...@gmail.com> #51
cl...@google.com <cl...@google.com> #52
paging-common 3.2.0-alpha06
?
il...@google.com <il...@google.com> #53
Re
so...@gmail.com <so...@gmail.com> #54
is...@gmail.com <is...@gmail.com> #55
Regarding the workaround from firstVisibleItemIndex
and firstVisibleItemScrollOffset
to continue to remain the same in case other code depends on them, it looks like the workaround should be modified to this?
@Composable
fun <T : Any> LazyPagingItems<T>.rememberLazyGridState(): LazyGridState {
val state = androidx.compose.foundation.lazy.grid.rememberLazyGridState()
return when (itemCount) {
// Return a different LazyListState instance.
0 -> remember(this) {
LazyGridState(
firstVisibleItemIndex = state.firstVisibleItemIndex,
firstVisibleItemScrollOffset = state.firstVisibleItemScrollOffset
)
}
// Return rememberLazyListState (normal case).
else -> state
}
}
h9...@gmail.com <h9...@gmail.com> #56
If there is a combined flow, cachedIn does not seem to work. Could you please confirm?
val pager = pager.flow
.map { pagingData ->
pagingData.map {
// map items
}
}
.cachedIn(scope)
.combine(otherFlow) { pagingData, otherFlow ->
pagingData.map{
// something
}
}
.cachedIn(scope)
If you call the pager again with collectAsLazyPagingItems()
, LoadState will be called LoadState.Loading
rather than LoadState.NotLoading
.
cl...@google.com <cl...@google.com> #57
Re
jo...@mozilla.com <jo...@mozilla.com> #58
The workarounds, like in
il...@google.com <il...@google.com> #59
Re
Please file a new issue with a sample project that reproduces your issue if you are seeing something different.
pa...@gmail.com <pa...@gmail.com> #60
im having a similar problem as
cl...@google.com <cl...@google.com> #61
Re
pr...@gmail.com <pr...@gmail.com> #62
@Composable
fun <T : Any> LazyPagingItems<T>.rememberLazyListState(): LazyListState {
val state = androidx.compose.foundation.lazy.rememberLazyListState()
val scrollIndex = rememberSaveable { mutableIntStateOf(0) }
val coroutineScope = rememberCoroutineScope()
// After recreation, LazyPagingItems first return 0 items, then the cached items.
// This behavior/issue is resetting the LazyListState scroll position.
return when (itemCount) {
// Return a different LazyListState instance.
0 -> rememberSaveable(saver = LazyListState.Saver) {
scrollIndex.intValue = state.firstVisibleItemIndex
LazyListState(state.firstVisibleItemIndex, state.firstVisibleItemScrollOffset)
}
else -> {
if(scrollIndex.intValue in 1..<itemCount) {
// Return state after scrolling.
LaunchedEffect("") {
coroutineScope.launch {
state.animateScrollToItem(scrollIndex.intValue, state.firstVisibleItemScrollOffset)
scrollIndex.intValue = 0
}
}
}
state
}
}
}
se...@gmail.com <se...@gmail.com> #63
I want to share my case with a positive result.
I use compose paging 3 (api + room), navigation.
This is my case in detail.
1. Screen A (list with api + room pagination)
2. Screen B (details + changing data in the database by item ID)
When I changed the data on screen B and returned to screen A, the position was reset.
The reason was as follows. When my LazyPagerItems<*> object was with ItemCount == 0, I used item {} to show placeholder. That was the reason! When I started using items even with ItemCount == 0, the position reset stopped happening.
Bad Case:
Lazy Column() {
when {
values == null || values.itemCount == 0 -> item {} //simple item
items () {} //for paging items
}
}
Nice Case:
Lazy Column() {
when {
values == null -> item {} //simple item
items (
count = values.itemCount,
) {} //for paging items
}
}
Then I started adding elements to LazyColumn and making it combined. In this case, it also reset the position! By removing the item at the beginning, the list began to work correctly.
Bad Case:
Lazy Column() {
item {} //simple item
item {} //simple item
items () {} //for paging items
}
Nice Case:
Lazy Column() {
items () {} //for paging items
}
to...@gmail.com <to...@gmail.com> #64
Yes they do not want the if and placeholders to be inside the LazyColumn we are supposed to use if outside of the LazyColum.
The workaround is to use a fake lazystate until your data is loaded.
See for example solution
cl...@google.com <cl...@google.com> #65
re cachedIn()
, you shouldn't need a workaround. Can you upload a sample app for me to take a look?
to...@gmail.com <to...@gmail.com> #66
Cachein does not keep the data when the app is killed in the background or viewmodel is unloaded.
sa...@gmail.com <sa...@gmail.com> #67
to...@gmail.com <to...@gmail.com> #68
That's cute but you might actually want to read the issue.
hu...@nevix.tech <hu...@nevix.tech> #69
val pager = pager.flow
.map { pagingData ->
pagingData.map {
// map items
}
}
.cachedIn(scope)
.combine(otherFlow) { pagingData, otherFlow ->
pagingData.map{
// something
}
}
.cachedIn(scope)
my-version = androidx.paging:paging-compose:3.3.5
When otherFlow updates data, an error occurs: Attempt to collect twice from pageEventFlow, which is an illegal operation. Did you forget to call Flow<PagingData<*>>.cachedIn(coroutineScope)?
Description
Jetpack Compose release version: 1.0.0-alpha09 Android Studio Build: Build #AI-202.7319.50.2031.7049475, built on December 24, 2020
Steps to Reproduce:
NavHost
-ed composable screen containing aLazyColumn
built withLazyPagingItems
collected from a view modelResult: the LazyColumn is scrolled back to top
Expected: the scroll position should be remembered
Sample code that works:https://gist.github.com/CyrilFind/5c7d108dd8d030fe7a6a556e43f29f6f
If the
.collectAsLazyPagingItems()
line from this sample is done before declaring theNavHost
, it works as expected but if it is done inside thecomposable
block, it does not.