RecyclerView.ListAdapter падает при изменении данных - PullRequest
0 голосов
/ 28 ноября 2018

Я решил поиграть с новым RecyclerView.ListAdapter и попробовать, может ли это быть использовано в производстве.

Я планировал показать элемент-заполнитель (скелет), покасписочные элементы загружаются и затем переключаются на обычный список элементов, как только клиент получает данные.То, как я обрабатываю это в адаптере , заключается в том, что я передаю 'null' submitList () (таким образом, я знаю, что данные еще не загружены).

Первая часть этого работает очень хорошо, ListAdapter запускается и отображает элемент скелета, но после загрузки «реального» списка приложение вылетает.Причиной сбоя является то, что адаптер переходит непосредственно к onBindViewHolder () без предварительного вызова onCreateViewHolder () и из-за этого пытается связать данные с полямиобычный элемент, который не существует в элементе скелета.

До сих пор я не смог выяснить, почему он пропускает часть onCreateViewHolder () для первого элемента и переходит непосредственно всвязывание.Я проверил, возможно, была какая-то проблема с diffUtils , но эти два элемента (элемент скелета и «настоящий») явно различаются.(Короткое примечание: здесь по какой-то причине точки останова в двух функциях diffUtils никогда не срабатывают вообще. Я не уверен, является ли это также частью проблемы или это просто Android Studio проблема.)

Основные важные классы:

ListAdapter

class VIPSimilarAdsAdapter(context: Context, presenterInterface: BaseVIPContract.MVPAdapterPresenter) : ListAdapter<Ad, AdViewHolderFactory.AdBaseViewHolder>(SimilarAdsDiffCallback()) {

    private val presenterInterface: WeakReference<BaseVIPContract.MVPAdapterPresenter> = WeakReference(presenterInterface)
    private var showLoadingInidicator = true

    override fun submitList(list: List<Ad>?) {
        showLoadingInidicator = list == null
        super.submitList(list)
    }

    override fun getItemCount(): Int {
        return when (showLoadingInidicator) {
            true -> 1
            else -> super.getItemCount()
        }
    }

    override fun onBindViewHolder(@NonNull holder: AdViewHolderFactory.AdBaseViewHolder, position: Int) {
        if (!showLoadingInidicator) {
            getItem(position)?.let { safeAd ->
                CommonViewBinder.bindCommonFields(holder as AdViewHolderFactory.AdViewHolder, safeAd)
                AdViewBinder.bindAdFields(holder, safeAd)
                holder.itemView.setOnClickListener {
                    presenterInterface.get()?.onUserEventSimilarAdClicked(safeAd, position)
                }
            }
        }
    }

    @NonNull
    override fun onCreateViewHolder(@NonNull parent: ViewGroup, viewType: Int): AdViewHolderFactory.AdBaseViewHolder {
        return (when (showLoadingInidicator) {
            true -> AdViewHolderFactory.SkeletonViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.grid_item_skeleton, parent, false), ITEM_VIEW_TYPE_SKELETON)
            else -> AdViewHolderFactory.AdViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.grid_item_ad_basic, parent, false))
        })
    }
}

Обратный вызов DiffUtil

class SimilarAdsDiffCallback : DiffUtil.ItemCallback<Ad>() {
    override fun areItemsTheSame(oldItem: Ad, newItem: Ad): Boolean {
        return oldItem == newItem
    }

    override fun areContentsTheSame(oldItem: Ad, newItem: Ad): Boolean {
        return oldItem.id == newItem.id
    }
}

Адаптер вызывается просто с помощью

adAdapterSimilarAds.submitList(null)

в начале упражнения, а затем с

adAdapterSimilarAds.submitList(list)

после загрузки данных.

Надеюсь, что кто-то сталкивался с этой проблемой раньше и может мне помочь ...


Редактировать: вот трассировка стека аварии

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{4e5bcfd position=6 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent} androidx.recyclerview.widget.RecyclerView{3d89e2f VFED..... ......ID 0,1953-1080,2289 #7f090302 app:id/similar_ads_after_pos_1}, adapter:ebk.vip.similar_ads.VIPSimilarAdsAdapter@ac7dc3c, layout:androidx.recyclerview.widget.GridLayoutManager@e9b3dc5, context:ebk.vip.vip_core.VIPActivity@ecfbcc3
        at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5715)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5898)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
        at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
        at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:557)
        at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
        at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
        at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:171)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3875)
        at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3330)
        at android.view.View.measure(View.java:19857)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6083)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1464)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:758)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:640)
        at android.view.View.measure(View.java:19857)
        at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
        at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
        at android.view.View.measure(View.java:19857)
        at androidx.core.widget.NestedScrollView.measureChildWithMargins(NestedScrollView.java:1502)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
        at androidx.core.widget.NestedScrollView.onMeasure(NestedScrollView.java:556)
        at android.view.View.measure(View.java:19857)
        at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
        at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
        at android.view.View.measure(View.java:19857)
        at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
        at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
        at android.view.View.measure(View.java:19857)
        at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
        at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
        at android.view.View.measure(View.java:19857)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6083)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
        at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
        at android.view.View.measure(View.java:19857)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6083)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
        at android.view.View.measure(View.java:19857)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6083)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
        at android.view.View.measure(View.java:19857)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6083)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1464)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:758)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:640)
...