#android #android-recyclerview #android-diffutils #android-listadapter
#Android #android-recyclerview #android-diffutils #android-listadapter
Вопрос:
Я использую RecyclerView
with ListAdapter (который использует AsyncListDiffer для вычисления и анимации изменений при замене списка).
Проблема в том, что иногда, когда я вызываю submit()
для обновления RecyclerView новыми данными, он блокирует весь поток пользовательского интерфейса на 5-10 секунд. Это происходит после того, как я возобновляю действие (возвращаюсь с главного экрана), но я не уверен, является ли это причиной.
Я убедился, что
- представленный список содержит хорошие, ожидаемые данные
- используется
recyclerView.setHasFixedSize(true);
, поскольку он занимает все пространство экрана
Это дамп потока, пока устройство находится в этом состоянии отсутствия ответа (см. raw):
"main@10549" prio=5 runnable
java.lang.Thread.State: RUNNABLE
at java.util.ArrayList.get(ArrayList.java:315)
at android.support.v7.widget.OpReorderer.getLastMoveOutOfOrder(OpReorderer.java:215)
at android.support.v7.widget.OpReorderer.reorderOps(OpReorderer.java:33)
at android.support.v7.widget.AdapterHelper.preProcess(AdapterHelper.java:93)
at android.support.v7.widget.RecyclerView.processAdapterUpdatesAndSetAnimationFlags(RecyclerView.java:3583)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3829)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3639)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:4194)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:625)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:2001)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1844)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1753)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:396)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1189)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:142)
at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:41)
at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1556)
at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:888)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1231)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:396)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:396)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:396)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:2001)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1844)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1753)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:396)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:2769)
at android.view.View.layout(View.java:16967)
at android.view.ViewGroup.layout(ViewGroup.java:5584)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2547)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2250)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1321)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6732)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)
at android.view.Choreographer.doCallbacks(Choreographer.java:696)
at android.view.Choreographer.doFrame(Choreographer.java:631)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5740)
at java.lang.reflect.Method.invoke(Method.java:-1)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:766)
Вот мой обратный вызов DiffUtil:
private static final DiffUtil.ItemCallback<CoinTicker> DIFF_CALLBACK = new DiffUtil.ItemCallback<CoinTicker>() {
@Override
public boolean areItemsTheSame(
@NonNull CoinTicker oldTicker, @NonNull CoinTicker newTicker) {
// User properties may have changed if reloaded from the DB, but ID is fixed
return oldTicker.getSlug().equals(newTicker.getSlug()); // String
}
@Override
public boolean areContentsTheSame(
@NonNull CoinTicker oldTicker, @NonNull CoinTicker newTicker) {
// NOTE: if you use equals, your object must properly override Object#equals()
// Incorrectly returning false here will result in too many animations.
return oldTicker.equals(newTicker); // see below
}
@Override
public Object getChangePayload(@NonNull CoinTicker oldTicker, @NonNull CoinTicker newTicker) {
return newTicker.getComparisonPrice() - oldTicker.getComparisonPrice();
}
};
// equals for CoinTicker:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CoinTicker that = (CoinTicker) o;
return Double.compare(that.price, price) == 0 amp;amp; slug.equals(that.slug);
}
Что здесь может быть не так?
Комментарии:
1. Ты снова пришел, ЛОЛ!
2. Да, это отдельная и последняя проблема, с которой я столкнулся 🙂 Борюсь с этим уже один день: (
3. Я не вижу никаких проблем с приведенным выше кодом, можете ли вы предоставить снимки из вашего цикла?
4. Вы снова вызываете API, или это огромный список со множеством операций, которые нужно выполнить перед настройкой на adapter.
5. @IbrahimAli ты имеешь в виду это ?
Ответ №1:
Рад сообщить, что «исправить» очень просто:
recyclerView.setItemAnimator(null);
Меня не волнует анимация. Я просто хотел цветную флэш-анимацию для элементов, которые отображаются на экране, что я делаю в onBindViewHolder (), и это работает очень быстро, без каких-либо задержек!
Ответ №2:
Сравнение двух списков — дорогостоящая операция. Если вы имеете дело с огромными объемами данных, это может потребовать много ресурсов. Поэтому выполняйте свои операции DiffUtils в фоновом потоке или используйте AsyncListDiffer, который запускается в фоновом потоке сам по себе.
Комментарии:
1. Я использую,
ListAdapter
который используетAsyncListDiffer
.2. @Bolling Нет, это не фон, если вы используете его самостоятельно