Android Paging - PagedListAdapter

简介

Android JectPack 组件中Paging 是其中一个重要组件。Paging 是对RecyclerVew.adpater的扩展。本文介绍其中一个知识点,用于记录自己的学习历程。

Adapter

RecyclerView是Android中的一个重要组件,使用RecyclerView组件最为重要的一个是自定义Adapter。如果使用Paging需要继承PagedListAdapter。一般自定义Adapter代码如下。

public class CheeseAdapter extends PagedListAdapter<Cheese,CheeseViewHolder> {
    private static DiffUtil.ItemCallback<Cheese> diffCallBack = new DiffUtil.ItemCallback<Cheese>() {
        @Override
        public boolean areItemsTheSame(@NonNull Cheese oldItem, @NonNull Cheese newItem) {

            return oldItem.getId() == newItem.getId();
        }

        @Override
        public boolean areContentsTheSame(@NonNull Cheese oldItem, @NonNull Cheese newItem) {
            return oldItem.getName().equals(newItem.getName());
        }
    };
    public CheeseAdapter() {
        super(diffCallBack);
    }

    @NonNull
    @Override
    public CheeseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new CheeseViewHolder(parent);
    }

    @Override
    public void onBindViewHolder(@NonNull CheeseViewHolder holder, int position) {
        holder.bindTo(getItem(position));
    }
}

其中Cheese是自定义的显示item类,CheeseViewHolder是ViewHolder。

PagedListAdapter 简易类图

在这里插入图片描述

  1. PagedListAdapter 继承于RecyclerView.Adapter。表明这是一个RecyclerView.Adapter,并且扩展了RecyclerView.Adapter的功能。
  2. 扩展功能是支持异步差分更新功能。

装饰器模式

装饰器模式(Decorator Pattern),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更灵活。 ----《大话设计模式》
标准的装饰器模式类图
在这里插入图片描述

  • 被装饰对象抽象接口(Component)
  • 具体的被装饰对象(ConcreteCompoent),负责接收装饰器。
  • Decorator装饰角色。持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能
  • ConcreteDecorate具体装饰角色:负责给构件对象增加新的功能。

小结

可以通过装饰器模式对PagedListAdapter进行拆分理解,PagedListAdapter添加了异步差分更新内容。

更新流程

更新数据PagedList

PagedList 继承 AbstractList。说明这个是一个list。PagedList的功能参见源码的注释。
个人理解如下:

  1. pagedList 可以在多个线程进行传递和访问。
  2. 初始化之后,pagedList被UI主线程持有。

PagedList 初始化
Pagedlist 的初始化与DataSource 有关。当xxDataSource 重新isContiguous 为true是,初始化的是ContiguousPagedList。否则初始化为TiledPagedList。

更新具体流程

更新流程的接口调用关系是

  1. PagedListAdapter#submitList
  2. AsyncPagedListDiffer#submitList
  3. AdapterListUpdateCallback#onInserted 或者 onRemoved或者onMoved 或者onChanged
  4. RecyclerView.Adapter 的notifyItemxx通知接口

核心代码如下

public void submitList(@Nullable final PagedList<T> pagedList,
            @Nullable final Runnable commitCallback) {
        if (pagedList != null) {
			// 判断submit 的pagedList 是否和 已持有的pagedList 是同类型的
            if (mPagedList == null && mSnapshot == null) {
                mIsContiguous = pagedList.isContiguous();
            } else {
                if (pagedList.isContiguous() != mIsContiguous) {
                    throw new IllegalArgumentException("AsyncPagedListDiffer cannot handle both"
                            + " contiguous and non-contiguous lists.");
                }
            }
        }

        // incrementing generation means any currently-running diffs are discarded when they finish
        final int runGeneration = ++mMaxScheduledGeneration;

        if (pagedList == mPagedList) {
			// submit 的 pagedList 和当前持有的 pagedList相同,不做任何操作直接返回
            // nothing to do (Note - still had to inc generation, since may have ongoing work)
            if (commitCallback != null) {
                commitCallback.run();
            }
            return;
        }

        final PagedList<T> previous = (mSnapshot != null) ? mSnapshot : mPagedList;

        if (pagedList == null) {
			// submit 的 pagedList 为空,执行移除操作
            int removedCount = getItemCount();
            if (mPagedList != null) {
                mPagedList.removeWeakCallback(mPagedListCallback);
                mPagedList = null;
            } else if (mSnapshot != null) {
                mSnapshot = null;
            }
            // dispatch update callback after updating mPagedList/mSnapshot
            mUpdateCallback.onRemoved(0, removedCount);
            onCurrentListChanged(previous, null, commitCallback);
            return;
        }

        if (mPagedList == null && mSnapshot == null) {
			// 为持有 pagedList  则将 submit 的pagedList 直接插入
            // fast simple first insert
            mPagedList = pagedList;
            pagedList.addWeakCallback(null, mPagedListCallback);

            // dispatch update callback after updating mPagedList/mSnapshot
            mUpdateCallback.onInserted(0, pagedList.size());

            onCurrentListChanged(null, pagedList, commitCallback);
            return;
        }
		
        if (mPagedList != null) {
            // first update scheduled on this list, so capture mPages as a snapshot, removing
            // callbacks so we don't have resolve updates against a moving target
            mPagedList.removeWeakCallback(mPagedListCallback);
            mSnapshot = (PagedList<T>) mPagedList.snapshot();
            mPagedList = null;
        }

        if (mSnapshot == null || mPagedList != null) {
            throw new IllegalStateException("must be in snapshot state to diff");
        }

        final PagedList<T> oldSnapshot = mSnapshot;
        final PagedList<T> newSnapshot = (PagedList<T>) pagedList.snapshot();
        mConfig.getBackgroundThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                final DiffUtil.DiffResult result;
                result = PagedStorageDiffHelper.computeDiff(
                        oldSnapshot.mStorage,
                        newSnapshot.mStorage,
                        mConfig.getDiffCallback());

                mMainThreadExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        if (mMaxScheduledGeneration == runGeneration) {
                            latchPagedList(pagedList, newSnapshot, result,
                                    oldSnapshot.mLastLoad, commitCallback);
                        }
                    }
                });
            }
        });
    }

更新流程如下:

  1. 如果submit的pagedList 为null ,则直接移除Adapter显示数据。
  2. 如果submit的pagedList不为null,且Adapter持有的padedList为null,则执行插入数据操作,通过Adapter更新UI界面。
  3. 如果submit的pagedList不为null,且Adapter持有的padedList不为null,则通过DiffUtil执行差分更新。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值