СТАРЫЙ ОТВЕТ (рекомендуется 14 февраля 2020 г.):
После многих дней изучения варианта, вызывающего эту ошибку, следующее:
protected val pagedListConfig: PagedList.Config = PagedList.Config.Builder()
.setEnablePlaceholders(true) . <------------ set to false
.setPrefetchDistance(PREFETCH_DISTANCE_SIZE)
.setPageSize(DATABASE_PAGE_SIZE)
.setInitialLoadSizeHint(INITIAL_DATABASE_PAGE_SIZE)
.build()
поэтому просто установите setEnablePlaceholders(false)
, чтобы избежать того, чтобы этот случай не заметил, что это повлияет на прокрутку, заставив ее мигать при загрузке дополнительных данных, пока не будет исправлено из android sdk.
ОБНОВЛЕНО 1 (не рекомендуется, см. обновление 2):
Проблема возникает в основном при восстановлении уничтоженной активности / фрагмента. В моем случае у меня 4 фрагмента, я обновлял все списки сразу после восстановление, то есть я вставляю новые данные, вызывая многократный вызов наблюдаемого, вызывая многократный вызов mDiffer.submitList, по праву это не должно сбой, поскольку mDiffer выполняет всю работу в фоновом режиме, но я предполагаю, что есть синхронизация проблема между mDiffer Runnables
поэтому я решил минимизировать вызовы mDiffer.submitList следующими способами:
сохранение / восстановление фрагментов вкладки элементов:
общественное переопределение удовольствие onSaveInstanceState (savedInstanceState: Пачка) {super.onSaveInstanceState (savedInstanceState) supportFragmentManager.putFragment (savedInstanceState, itemsFragment1, itemsFragment1)} общественное переопределение удовольствие onRestoreInstanceState (savedInstanceState: Пачка) {super.onRestoreInstanceState (savedInstanceState) newsMainFragment = supportFragmentManager.getFragment (savedInstanceState , itemsFragment1) как ItemsFragment1? }
Убедитесь, что за раз отправляется только один список (игнорируя слишком много изменений и сохраняйте только последний):
abstract class MyPagedListAdapter<T, VH : RecyclerView.ViewHolder>
(diffCallback: DiffUtil.ItemCallback<T>) : PagedListAdapter<T, VH>
.(diffCallback) {
var submitting = false
val latestPage: Queue<PagedList<T>?> = LinkedList()
val runnable = Runnable {
synchronized(this) {
submitting = false
if (latestPage.size > 0) {
submitFromLatest()
}
}
}
override fun submitList(pagedList: PagedList<T>?) {
synchronized(this) {
if(latestPage.size > 0){
Log.d("MyPagedListAdapter","ignored ${latestPage.size}")
}
latestPage.clear()
latestPage.add(pagedList)
submitFromLatest()
}
}
fun submitFromLatest() {
synchronized(this) {
if (!submitting) {
submitting = true
if (latestPage.size > 1 || latestPage.size < 1) {
Crashlytics.logException(Throwable("latestPage size is ${latestPage.size}"))
Log.d("MyPagedListAdapter","latestPage size is ${latestPage.size}")
}
super.submitList(latestPage.poll(), runnable)
}
}
}
}
ОБНОВЛЕНИЕ 2 (исправлено, но не рекомендуется, см. обновление 3):
Это исправление обнаружит ошибку, но не предотвратит возникновение проблемы, поскольку она связана с классом обработчика из Android SDK, когда при попытке вызвать Handler.createAsync
некоторые старые устройства со старым SDK создадут синхронизированный обработчик, который приведет к сбою
В вашем адаптере, который расширяет PagedListAdapter
, добавьте следующее:
init {
try {
val mDiffer = PagedListAdapter::class.java.getDeclaredField("mDiffer")
val excecuter = AsyncPagedListDiffer::class.java.getDeclaredField("mMainThreadExecutor")
mDiffer.isAccessible = true
excecuter.isAccessible = true
val myDiffer = mDiffer.get(this) as AsyncPagedListDiffer<*>
val foreGround = object : Executor {
val mHandler = createAsync(Looper.getMainLooper())
override fun execute(command: Runnable?) {
try {
mHandler.post {
try {
command?.run()
} catch (e: Exception) {
e.printStackTrace()
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
excecuter.set(myDiffer, foreGround)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun createAsync(looper: Looper): Handler {
if (Build.VERSION.SDK_INT >= 28) {
return Handler.createAsync(looper)
}
if (Build.VERSION.SDK_INT >= 16) {
try {
return Handler::class.java.getDeclaredConstructor(Looper::class.java, Handler.Callback::class.java,
Boolean::class.javaPrimitiveType)
.newInstance(looper, null, true)
} catch (ignored: IllegalAccessException) {
} catch (ignored: InstantiationException) {
} catch (ignored: NoSuchMethodException) {
} catch (e: InvocationTargetException) {
return Handler(looper)
}
}
return Handler(looper)
}
Также, если вы используете Pro-Guard или R8, добавьте следующие правила:
-keep class androidx.paging.PagedListAdapter.** { *; }
-keep class androidx.paging.AsyncPagedListDiffer.** { *; }
ofc это обходной путь, поэтому при обновлении sdk будьте осторожны, чтобы имя не изменилось для отражения.
ОБНОВЛЕНИЕ 3 (14.02.2020):
использовать :
setEnablePlaceholders(false)
но после обновления библиотеки подкачки до:
implementation 'androidx.paging:paging-runtime-ktx:2.1.2'
проблема со вспышкой исправлена
person
Ahmed na
schedule
03.07.2019