Android JetPack学习笔记-Paging

目录

1.Paging2.x

   (1)使用

    (2)源码分析

        【1】初次如何加载数据

        【2】初次刷新UI

        【3】后续的追加页面


1.Paging2.x

   (1)使用

        javabean:

public class Person {

    private String id;
    private String name;
    private String sex;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
        Person person = (Person) o;
        return getId().equals(person.getId()) &&
                getName().equals(person.getName()) &&
                getSex().equals(person.getSex());
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    public int hashCode() {
        return Objects.hash(getId(), getName(), getSex());
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

        ViewModel

public class PersonViewModel extends ViewModel {

    private final LiveData<PagedList<Person>> pagedListLiveData;

    public PersonViewModel() {
        // @1 Factory 的创建
        DataSource.Factory<Integer, Person> factory = new PersonDataSourceFactory();

        /*PagedList.Config pConfig = new PagedList.Config.Builder()
                .setPageSize(20)
                .setEnablePlaceholders(true)
                .setInitialLoadSizeHint(20)
                .build();*/

        // @1 Factory
        pagedListLiveData = new LivePagedListBuilder<Integer, Person>(factory,
                new PagedList.Config.Builder()
                        .setEnablePlaceholders(true)
                        .setPageSize(20)
                        .build()).build();
    }

    public LiveData<PagedList<Person>> getPagedListLiveData() {
        return pagedListLiveData;
    }
}

        Adapter

public class RecyclerPagingAdapter extends PagedListAdapter<Person, RecyclerPagingAdapter.MyRecyclerViewHolder> {

    //需要oldPerson与新 newPerson 比较才能得出变化的数据
    private static DiffUtil.ItemCallback<Person> DIFF_STUDENT =
            new DiffUtil.ItemCallback<Person>() {
                // 判断Item是否已经存在
                @Override
                public boolean areItemsTheSame(Person oldPerson, Person newPerson) {
                    return oldPerson.getId().equals(newPerson.getId());
                }

                // 如果Item已经存在则会调用此方法,判断Item的内容是否一致
                @Override
                public boolean areContentsTheSame(Person oldPerson, Person newPerson) {
                    return oldPerson.equals(newPerson);
                }
            };

    protected RecyclerPagingAdapter() {
        super(DIFF_STUDENT);
    }

    ......
}

        Factory

public class PersonDataSourceFactory extends DataSource.Factory<Integer, Person> {

    @NonNull
    @Override
    public DataSource<Integer, Person> create() {
        return new CustomPageDataSource(new DataRepository());
    }
}

        

public class CustomPageDataSource extends PageKeyedDataSource<Integer, Person> {

    private DataRepository dataRepository;

    CustomPageDataSource(DataRepository dataRepository) {
        this.dataRepository = dataRepository;
    }

    // loadInitial 初始加载数据
    @Override
    public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, Person> callback) {
        List<Person> dataList = dataRepository.initData(params.requestedLoadSize);
        callback.onResult(dataList, null, 2);
    }

    // loadBefore 向前分页加载数据
    @Override
    public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Person> callback) {
        List<Person> dataList = dataRepository.loadPageData(params.key, params.requestedLoadSize);
        if (dataList != null) {
            callback.onResult(dataList, params.key - 1);
        }
    }

    // loadAfter 向后分页加载数据
    @Override
    public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Person> callback) {
        List<Person> dataList = dataRepository.loadPageData(params.key, params.requestedLoadSize);
        if (dataList != null) {
            callback.onResult(dataList, params.key + 1);
        }
    }
}

        仓库类

public class DataRepository {

    private List<Person> dataList = new ArrayList<>();

    public DataRepository() {
        for (int i = 0; i < 1000; i++) {
            Person person = new Person();
            person.setId("ID号是:" + i);
            person.setName("我名称:" + i);
            person.setSex("我性别:" + i);
            dataList.add(person);
        }
    }

    public List<Person> initData(int size) {
        return dataList.subList(0, size);
    }

    public List<Person> loadPageData(int page, int size) {
        int totalPage;
        if (dataList.size() % size == 0) {
            totalPage = dataList.size() / size;
        } else {
            totalPage = dataList.size() / size + 1;
        }

        if (page > totalPage || page < 1) {
            return null;
        }
        if (page == totalPage) {
            return dataList.subList((page - 1) * size, dataList.size());
        }
        return dataList.subList((page - 1) * size, page * size);
    }
}

        activity

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recycle_view);
        recyclerPagingAdapter = new RecyclerPagingAdapter();

        personViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(PersonViewModel.class);
        personViewModel.getPagedListLiveData().observe(this, new Observer<PagedList<Person>>() {
            @Override
            public void onChanged(PagedList<Person> persons) {
                recyclerPagingAdapter.submitList(persons);
            }
        });

        recyclerView.setAdapter(recyclerPagingAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }

        这样我们就做到了自动分页,自动请求网络请求刷新UI。

    (2)源码分析

        【1】初次如何加载数据

        首先咱们从入口出发,我们在activity获取了viewmodel的livedata进行订阅。咱们就从viewmodel出发。看到了在viewmodel中通过LivePagedListBuilder建造者模式创建出来的livedata。

    public LiveData<PagedList<Value>> build() {
        return create(mInitialLoadKey, mConfig, mBoundaryCallback, mDataSourceFactory,
                ArchTaskExecutor.getMainThreadExecutor(), mFetchExecutor);
    }

    @SuppressLint("RestrictedApi")
    private static <Key, Value> LiveData<PagedList<Value>> create(
            @Nullable final Key initialLoadKey,
            @NonNull final PagedList.Config config,
            @Nullable final PagedList.BoundaryCallback boundaryCallback,
            @NonNull final DataSource.Factory<Key, Value> dataSourceFactory,
            @NonNull final Executor notifyExecutor,
            @NonNull final Executor fetchExecutor) {
        return new ComputableLiveData<PagedList<Value>>(fetchExecutor) {
            @Nullable
            private PagedList<Value> mList;
            @Nullable
            private DataSource<Key, Value> mDataSource;

            private final DataSource.InvalidatedCallback mCallback =
                    new DataSource.InvalidatedCallback() {
                        @Override
                        public void onInvalidated() {
                            invalidate();
                        }
                    };

           ......
        }.getLiveData();
    }

        他的建造者模式通过源码我们看到她给我们创建了一个ComputableLiveData的类。那具体实现我们就要去其内部看看。

    public ComputableLiveData(@NonNull Executor executor) {
        mExecutor = executor;//默认咱们传过来的是IO
        //创建一个livedata,当它所订阅的生命组件到达活跃状态时会触发
        mLiveData = new LiveData<T>() {
            @Override
            protected void onActive() {
                mExecutor.execute(mRefreshRunnable);
            }
        };
    }

    //返回构造方法里初始化的livedata
    public LiveData<T> getLiveData() {
        return mLiveData;
    }

    final Runnable mRefreshRunnable = new Runnable() {
        @WorkerThread
        @Override
        public void run() {
            boolean computed;
            do {
                computed = false;
                //通过CAS自旋来判断值
                //当初次时会满足条件
                if (mComputing.compareAndSet(false, true)) {
                    try {
                        T value = null;
                        //当初次时会满足条件
                        while (mInvalid.compareAndSet(true, false)) {
                            computed = true;
                            //计算值
                            value = compute();
                        }
                        if (computed) {
                            //由于咱们传过来的是IO线程,所以用postValue进行传值
                            //这边livedata一传值,就会触发我们activity的订阅就会向adapter执行submitList,进行数据更新
                            mLiveData.postValue(value);
                        }
                    } finally {
                        mComputing.set(false);
                    }
                }
            } while (computed && mInvalid.get());
        }
    };

        那首次数据进行改变咱们看到这边就大概明白了,但是它compute都做了些啥,咱们不知道。compute方法在我们之前返回的ComputableLiveData类中有实现。

            @override
            protected PagedList<Value> compute() {
                @Nullable Key initializeKey = initialLoadKey;
                if (mList != null) {
                    initializeKey = (Key) mList.getLastKey();
                }

                do {
                    if (mDataSource != null) {
                        mDataSource.removeInvalidatedCallback(mCallback);
                    }
                    //获取咱们factory中create创建的数据源
                    mDataSource = dataSourceFactory.create();
                    mDataSource.addInvalidatedCallback(mCallback);
                    //我们传过来的参数,几乎都在此被这个类构建使用
                    mList = new PagedList.Builder<>(mDataSource, config)
                            .setNotifyExecutor(notifyExecutor)//Main线程
                            .setFetchExecutor(fetchExecutor)//IO线程
                            .setBoundaryCallback(boundaryCallback)
                            .setInitialKey(initializeKey)
                            .build();
                } while (mList.isDetached());
                return mList;
            }

        看到参数几乎都用于构建PagedList,看看内部

        public PagedList<Value> build() {
            if (mNotifyExecutor == null) {
                throw new IllegalArgumentException("MainThreadExecutor required");
            }
            if (mFetchExecutor == null) {
                throw new IllegalArgumentException("BackgroundThreadExecutor required");
            }

            return PagedList.create(
                    mDataSource,
                    mNotifyExecutor,
                    mFetchExecutor,
                    mBoundaryCallback,
                    mConfig,
                    mInitialKey);
        }

    static <K, T> PagedList<T> create(@NonNull DataSource<K, T> dataSource,
            @NonNull Executor notifyExecutor,
            @NonNull Executor fetchExecutor,
            @Nullable BoundaryCallback<T> boundaryCallback,
            @NonNull Config config,
            @Nullable K key) {
        //判断源是否连续 || 是否存在占位
        if (dataSource.isContiguous() || !config.enablePlaceholders) {
            int lastLoad = ContiguousPagedList.LAST_LOAD_UNSPECIFIED;
            //不存在占位 且 源不连续
            if (!dataSource.isContiguous()) {
                //创建单源PositionalDataSource
                dataSource = (DataSource<K, T>) ((PositionalDataSource<T>) dataSource)
                        .wrapAsContiguousWithoutPlaceholders();
                if (key != null) {
                    lastLoad = (Integer) key;
                }
            }
            ContiguousDataSource<K, T> contigDataSource = (ContiguousDataSource<K, T>) dataSource;
            //创建ContiguousPagedList实例
            return new ContiguousPagedList<>(contigDataSource,
                    notifyExecutor,
                    fetchExecutor,
                    boundaryCallback,
                    config,
                    key,
                    lastLoad);
        } else {
            return new TiledPagedList<>((PositionalDataSource<T>) dataSource,
                    notifyExecutor,
                    fetchExecutor,
                    boundaryCallback,
                    config,
                    (key != null) ? (Integer) key : 0);
        }
    }

        我们以连续源为例,ContiguousPagedList继续看。

    ContiguousPagedList(
            @NonNull ContiguousDataSource<K, V> dataSource,
            @NonNull Executor mainThreadExecutor,
            @NonNull Executor backgroundThreadExecutor,
            @Nullable BoundaryCallback<V> boundaryCallback,
            @NonNull Config config,
            final @Nullable K key,
            int lastLoad) {
        super(new PagedStorage<V>(), mainThreadExecutor, backgroundThreadExecutor,
                boundaryCallback, config);
        mDataSource = dataSource;
        mLastLoad = lastLoad;
        //判断数据源是否失效
        if (mDataSource.isInvalid()) {
            detach();
        } else {
            //初始化加载
            mDataSource.dispatchLoadInitial(key,
                    mConfig.initialLoadSizeHint,
                    mConfig.pageSize,
                    mConfig.enablePlaceholders,
                    mMainThreadExecutor,
                    mReceiver);
        }
        mShouldTrim = mDataSource.supportsPageDropping()
                && mConfig.maxSize != Config.MAX_SIZE_UNBOUNDED;
    }

        到这咱们就到了初始化加载数据了,看它的内部是个抽象类。我们的例子以PageKeyedDataSource为例。

    @Override
    final void dispatchLoadInitial(@Nullable Key key, int initialLoadSize, int pageSize,
            boolean enablePlaceholders, @NonNull Executor mainThreadExecutor,
            @NonNull PageResult.Receiver<Value> receiver) {
        LoadInitialCallbackImpl<Key, Value> callback =
                new LoadInitialCallbackImpl<>(this, enablePlaceholders, receiver);//(1)创建了一个回调
        loadInitial(new LoadInitialParams<Key>(initialLoadSize, enablePlaceholders), callback);//(2)真正加载数据的方法
        callback.mCallbackHelper.setPostExecutor(mainThreadExecutor);//设置回调的线程为主线程
    }

    (1)

        LoadInitialCallbackImpl(@NonNull PageKeyedDataSource<Key, Value> dataSource,
                boolean countingEnabled, @NonNull PageResult.Receiver<Value> receiver) {
            mCallbackHelper = new LoadCallbackHelper<>(
                    dataSource, PageResult.INIT, null, receiver);//设置状态为INIT
            mDataSource = dataSource;
            mCountingEnabled = countingEnabled;
        }

    (2)loadInitial是我们实现的DataSource中实现的方法

    @Override
    public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, Person> callback) {
        //在这里我们就进行网络请求数据了
        List<Person> dataList = dataRepository.initData(params.requestedLoadSize);
        //调用回调的onResult
        callback.onResult(dataList, null, 2);
    }

         到这,咱们就跑到了LoadInitialCallback.onResult方法里了。

        public void onResult(@NonNull List<Value> data, @Nullable Key previousPageKey,
                @Nullable Key nextPageKey) {
            if (!mCallbackHelper.dispatchInvalidResultIfInvalid()) {
                //key值赋值
                mDataSource.initKeys(previousPageKey, nextPageKey);
                //主要分发结果
                mCallbackHelper.dispatchResultToReceiver(new PageResult<>(data, 0, 0, 0));
            }
        }
        //判断是否有效
        boolean dispatchInvalidResultIfInvalid() {
            if (mDataSource.isInvalid()) {
                dispatchResultToReceiver(PageResult.<T>getInvalidResult());
                return true;
            }
            return false;
        }

        void dispatchResultToReceiver(final @NonNull PageResult<T> result) {
            Executor executor;
            synchronized (mSignalLock) {
                if (mHasSignalled) {
                    throw new IllegalStateException(
                            "callback.onResult already called, cannot call again.");
                }
                mHasSignalled = true;
                executor = mPostExecutor;//主线程
            }

            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        //计算页面结果,mReceiver在ContiguousPagedList类中为成员变量
                        mReceiver.onPageResult(mResultType, result);
                    }
                });
            } else {
                mReceiver.onPageResult(mResultType, result);
            }
        }

        最终执行了onPageResult

public void onPageResult(@PageResult.ResultType int resultType,
                @NonNull PageResult<V> pageResult) {
            ......
            List<V> page = pageResult.page;
            if (resultType == PageResult.INIT) {
                //状态为初始化时执行
                mStorage.init(pageResult.leadingNulls, page, pageResult.trailingNulls,
                        pageResult.positionOffset, ContiguousPagedList.this);
                if (mLastLoad == LAST_LOAD_UNSPECIFIED) {
                    mLastLoad =
                            pageResult.leadingNulls + pageResult.positionOffset + page.size() / 2;
                }
            } else {
                boolean trimFromFront = mLastLoad > mStorage.getMiddleOfLoadedRange();
                boolean skipNewPage = mShouldTrim
                        && mStorage.shouldPreTrimNewPage(
                                mConfig.maxSize, mRequiredRemainder, page.size());
                if (resultType == PageResult.APPEND) {
                    //状态为追加页面
                    if (skipNewPage && !trimFromFront) {
                        //没有增加任何数据
                        mAppendItemsRequested = 0;
                        mAppendWorkerState = READY_TO_FETCH;
                    } else {
                        //主要执行
                        mStorage.appendPage(page, ContiguousPagedList.this);
                    }
                } else if (resultType == PageResult.PREPEND) {
                    if (skipNewPage && trimFromFront) {
                        //没有增加任何数据
                        mPrependItemsRequested = 0;
                        mPrependWorkerState = READY_TO_FETCH;
                    } else {
                        //主要执行
                        mStorage.prependPage(page, ContiguousPagedList.this);
                    }
                } else {
                    throw new IllegalArgumentException("unexpected resultType " + resultType);
                }

            ......
        }

        可以看到主要处理就在这边的onPageResult方法,调用了Storage进行我们的初始化、往后追加页面和向前追加页面。我们先看init。初始化整个流程还没走完。

    //PagedStorage中的方法
    void init(int leadingNulls, @NonNull List<T> page, int trailingNulls, int positionOffset,
            @NonNull Callback callback) {
        init(leadingNulls, page, trailingNulls, positionOffset);
        callback.onInitialized(size());
    }

    //ContiguousPagedList中的方法
    public void onInitialized(int count) {
        notifyInserted(0, count);
        // simple heuristic to decide if, when dropping pages, we should replace with placeholders
        mReplacePagesWithNulls =
                mStorage.getLeadingNullCount() > 0 || mStorage.getTrailingNullCount() > 0;
    }

    //PagedList中的方法
    void notifyInserted(int position, int count) {
        //由于我们初始化,所以当前mCallback中还没有存在任何的回调,所以无法通过回调去执行更新插入
        if (count != 0) {
            for (int i = mCallbacks.size() - 1; i >= 0; i--) {
                final Callback callback = mCallbacks.get(i).get();
                if (callback != null) {
                    callback.onInserted(position, count);
                }
            }
        }
    }

        到这我们compute一路走下来就完全走完了,一路上我们通过factory创建了对应的dataSource,通过dataSource请求数据之后,进行了storage的初始化。最后就执行了livedata.postValue进行初次的传值。(当然如果创建了BoundaryCallback也会对应执行)。数据进行了改变,熟悉livedata就直到会走到我们activity中的observer方法里了。

        【2】初次刷新UI

        personViewModel.getPagedListLiveData().observe(this, new Observer<PagedList<Person>>() {
            @Override
            public void onChanged(PagedList<Person> persons) {
                recyclerPagingAdapter.submitList(persons);//提交数据入口
            }
        });
    //我们在adapter中创建的callback
    protected PagedListAdapter(@NonNull DiffUtil.ItemCallback<T> diffCallback) {
        mDiffer = new AsyncPagedListDiffer<>(this, diffCallback);
        mDiffer.addPagedListListener(mListener);
    }

    public void submitList(@Nullable PagedList<T> pagedList) {
        mDiffer.submitList(pagedList);
    }
    public AsyncPagedListDiffer(@NonNull RecyclerView.Adapter adapter,
            @NonNull DiffUtil.ItemCallback<T> diffCallback) {
        mUpdateCallback = new AdapterListUpdateCallback(adapter);
        mConfig = new AsyncDifferConfig.Builder<>(diffCallback).build();
    }

    public void submitList(@Nullable final PagedList<T> pagedList) {
        submitList(pagedList, null);
    }

    public void submitList(@Nullable final PagedList<T> pagedList,
            @Nullable final Runnable commitCallback) {
        ......

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

        if (pagedList == null) {
            int removedCount = getItemCount();
            if (mPagedList != null) {
                mPagedList.removeWeakCallback(mPagedListCallback);
                mPagedList = null;
            } else if (mSnapshot != null) {
                mSnapshot = null;
            }
            mUpdateCallback.onRemoved(0, removedCount);
            onCurrentListChanged(previous, null, commitCallback);
            return;
        }

        if (mPagedList == null && mSnapshot == null) {
            //上一页数据为空 且 快照不存在
            mPagedList = pagedList;
            //之前说初始化所以mCallback为空,到这里向我们mCallback存回调
            pagedList.addWeakCallback(null, mPagedListCallback);
            //真正的刷新
            mUpdateCallback.onInserted(0, pagedList.size());

            onCurrentListChanged(null, pagedList, commitCallback);
            return;
        }
        ......
    }
    private final RecyclerView.Adapter mAdapter;

    public AdapterListUpdateCallback(@NonNull RecyclerView.Adapter adapter) {
        mAdapter = adapter;
    }

    @Override
    public void onInserted(int position, int count) {
        mAdapter.notifyItemRangeInserted(position, count);
    }

        到此为止,咱们的刷新UI就结束了,但是我们仔细看它是如何对adapter进行修改的。我们类实现自PagedListAdapter,看看它怎么存我们数据的。

    @Nullable
    protected T getItem(int position) {
        return mDiffer.getItem(position);
    }

    @Override
    public int getItemCount() {
        return mDiffer.getItemCount();
    }
    public int getItemCount() {
        if (mPagedList != null) {
            return mPagedList.size();
        }

        return mSnapshot == null ? 0 : mSnapshot.size();
    }

    public T getItem(int index) {
        if (mPagedList == null) {
            if (mSnapshot == null) {
                throw new IndexOutOfBoundsException(
                        "Item count is zero, getItem() call is invalid");
            } else {
                return mSnapshot.get(index);
            }
        }

        mPagedList.loadAround(index);
        return mPagedList.get(index);//从数据列表中获取数据
    }

        到这,首次刷新UI大家就能了解了,数据传递在AsyncPagedListDiffer此类中,有多少数据找它拿,然后我们在我们些的adapter的onBindViewHolder方法直接获取对应实例,直接赋值给控件即可。

        【3】后续的追加页面

        我们并写代码主动的追加,它是怎么实现的呢。其实看到刚才的getItem我们就已经看到了,它在获取Item时有调用PagedList的方法。

    public void loadAround(int index) {
        if (index < 0 || index >= size()) {
            //当前下标越界判断
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size());
        }

        mLastLoad = index + getPositionOffset();
        //主要加载方法
        loadAroundInternal(index);

        mLowestIndexAccessed = Math.min(mLowestIndexAccessed, index);
        mHighestIndexAccessed = Math.max(mHighestIndexAccessed, index);

        tryDispatchBoundaryCallbacks(true);
    }

       执行了loadAroundInternal方法,我们这是以连续源为例的,所以我们去ContiguousPagedList看

    protected void loadAroundInternal(int index) {
        int prependItems = getPrependItemsRequested(mConfig.prefetchDistance, index,
                mStorage.getLeadingNullCount());
        int appendItems = getAppendItemsRequested(mConfig.prefetchDistance, index,
                mStorage.getLeadingNullCount() + mStorage.getStorageCount());

        mPrependItemsRequested = Math.max(prependItems, mPrependItemsRequested);
        //判断是否为向前追加
        if (mPrependItemsRequested > 0) {
            schedulePrepend();
        }

        mAppendItemsRequested = Math.max(appendItems, mAppendItemsRequested);
        //判断是否为向后追加
        if (mAppendItemsRequested > 0) {
            scheduleAppend();
        }
    }

        我们这边就以往后追加看

    private void scheduleAppend() {
        if (mAppendWorkerState != READY_TO_FETCH) {
            return;
        }
        mAppendWorkerState = FETCHING;
        final int position = mStorage.getLeadingNullCount()
                + mStorage.getStorageCount() - 1 + mStorage.getPositionOffset();
        final V item = mStorage.getLastLoadedItem();
        mBackgroundThreadExecutor.execute(new Runnable() {
            @Override
            public void run() {
                if (isDetached()) {
                    return;
                }
                if (mDataSource.isInvalid()) {
                    detach();
                } else {
                    //执行向后请求方法
                    mDataSource.dispatchLoadAfter(position, item, mConfig.pageSize,
                            mMainThreadExecutor, mReceiver);
                }
            }
        });
    }
    @Override
    final void dispatchLoadAfter(int currentEndIndex, @NonNull Value currentEndItem,
            int pageSize, @NonNull Executor mainThreadExecutor,
            @NonNull PageResult.Receiver<Value> receiver) {
        @Nullable Key key = getNextKey();
        if (key != null) {
            //这里就直接调用了自己实现的DataSource的loadAfter方法,给LoadCallbackImpl设置状态为APPEND
            loadAfter(new LoadParams<>(key, pageSize),
                    new LoadCallbackImpl<>(this, PageResult.APPEND, mainThreadExecutor, receiver));
        } else {
            receiver.onPageResult(PageResult.APPEND, PageResult.<Value>getEmptyResult());
        }
    }
    @Override
    public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Person> callback) {
        List<Person> dataList = dataRepository.loadPageData(params.key, params.requestedLoadSize);
        if (dataList != null) {
            //数据交给回调
            callback.onResult(dataList, params.key + 1);
        }
    }
        @Override
        public void onResult(@NonNull List<Value> data, @Nullable Key adjacentPageKey) {
            if (!mCallbackHelper.dispatchInvalidResultIfInvalid()) {
                //判断type是往前追加,还是往后追加,设置对应的key
                if (mCallbackHelper.mResultType == PageResult.APPEND) {
                    mDataSource.setNextKey(adjacentPageKey);
                } else {
                    mDataSource.setPreviousKey(adjacentPageKey);
                }
                //最终还是调用到了dispatchResultToReceiver这个方法
                mCallbackHelper.dispatchResultToReceiver(new PageResult<>(data, 0, 0, 0));
            }
        }

        最后还是调用到了咱们的dispatchResultToReceiver方法,后续方法就不粘了,直接粘onPageResult方法。

public void onPageResult(@PageResult.ResultType int resultType,
                @NonNull PageResult<V> pageResult) {
            ......
            List<V> page = pageResult.page;
            if (resultType == PageResult.INIT) {
                ......
            } else {
                boolean trimFromFront = mLastLoad > mStorage.getMiddleOfLoadedRange();
                boolean skipNewPage = mShouldTrim
                        && mStorage.shouldPreTrimNewPage(
                                mConfig.maxSize, mRequiredRemainder, page.size());
                if (resultType == PageResult.APPEND) {
                    //状态为追加页面
                    if (skipNewPage && !trimFromFront) {
                        //没有增加任何数据
                        mAppendItemsRequested = 0;
                        mAppendWorkerState = READY_TO_FETCH;
                    } else {
                        //主要执行
                        mStorage.appendPage(page, ContiguousPagedList.this);
                    }
                } else if (resultType == PageResult.PREPEND) {
                    if (skipNewPage && trimFromFront) {
                        //没有增加任何数据
                        mPrependItemsRequested = 0;
                        mPrependWorkerState = READY_TO_FETCH;
                    } else {
                        //主要执行
                        mStorage.prependPage(page, ContiguousPagedList.this);
                    }
                } else {
                    throw new IllegalArgumentException("unexpected resultType " + resultType);
                }

            ......
        }
    void appendPage(@NonNull List<T> page, @NonNull Callback callback) {
        final int count = page.size();
        ......

        mPages.add(page);
        mLoadedCount += count;
        mStorageCount += count;

        final int changedCount = Math.min(mTrailingNullCount, count);
        final int addedCount = count - changedCount;

        if (changedCount != 0) {
            mTrailingNullCount -= changedCount;
        }
        mNumberAppended += count;
        callback.onPageAppended(mLeadingNullCount + mStorageCount - count,
                changedCount, addedCount);
    }

    public void onPageAppended(int endPosition, int changedCount, int addedCount) {
        // consider whether to post more work, now that a page is fully appended
        mAppendItemsRequested = mAppendItemsRequested - changedCount - addedCount;
        mAppendWorkerState = READY_TO_FETCH;
        if (mAppendItemsRequested > 0) {
            // not done appending, keep going
            scheduleAppend();
        }

        // finally dispatch callbacks, after append may have already been scheduled
        notifyChanged(endPosition, changedCount);
        notifyInserted(endPosition + changedCount, addedCount);
    }

        这样就去刷新我们的数据了。但是我自己看的时候有疑问,后续的刷新啥时候有改动到mPagedList的大小。于是我跑到PagedList中看了这些方法。

    @Override
    public int size() {
        return mStorage.size();
    }

    public List<T> snapshot() {
        if (isImmutable()) {
            return this;
        }
        return new SnapshotPagedList<>(this);
    }

    @Override
    @Nullable
    public T get(int index) {
        T item = mStorage.get(index);
        if (item != null) {
            mLastItem = item;
        }
        return item;
    }

        数据它是存储在storage中的,所以这样我们就闭合了。

        总结:2.x-首先我们构建了一个LiveData然后在订阅的生命周期组件到达活跃时会触发去计算,计算中会通过我们实现的factory去创建我们的dataSource。接着创建PagedList中会执行我们dataSource的初始化请求,请求完毕后初始化storage,将数据存储。到此初始化和请求接口就走完了。然后postValue将我们的数据传递,主要实现是在父类的成员变量mDiffer中。adapter数据从这取。我们的数据存自storage。后续的追加页面由getItem来触发,后续数据增加storage的数据会改变,然后在通知adapter刷新。

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值