PS:原文首发于微信公众号:躬行之(jzman-blog)
阅读本文之前,可先阅读同系列 Android Jetpack 组件文章如下 :
- Android Jetpack组件之Lifecycle篇
- Android Jetpack组件之LiveData详解
- Android Jetpack组件之ViewModel篇
- Android Jetpack组件之DataBinding详解
- Android Jetpack组件之使用可观察的数据对象
- Android Jetpack组件之Paging Library使用篇
接着上篇从 LiveData 的 observer 方法进入
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 记住这个LifecycleBoundObserver,后面有用
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 添加Observer,具体是LifecycleBoundObserver
owner.getLifecycle().addObserver(wrapper);
}
继续查看 LifecycleRegistry 的 addObserver 方法,源码如下:
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
// ...
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
// ObserverWithState的dispatchEvent方法
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
popParentState();
// mState / subling may have been changed recalculate
targetState = calculateTargetState(observer);
}
// ...
}
static class ObserverWithState {
State mState;
LifecycleEventObserver mLifecycleObserver;
ObserverWithState(LifecycleObserver observer, State initialState) {
mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
mState = initialState;
}
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = getStateAfter(event);
mState = min(mState, newState);
// 实际调用的是LifecycleBoundObserver的onStateChanged方法
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
}
继续查看 LiveData 的内部类 LifecycleBoundObserver 的 onStateChanged 方法,源码如下:
// 方法
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
// Lifecycle组件监听的生命周期方法回调
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
// 查看源码shouldBeActive方法知,只要Activity的状态在ON_START之后就返回true
activeStateChanged(shouldBeActive());
}
// activeStateChanged方法
void activeStateChanged(boolean newActive) {
// mActive默认false,所以不成立
// 如果第二次执行mActive为false,则不继续处理,最终的结果就是不会回到onChanged方法
if (newActive == mActive) {
return;
}
// 第一次执行完后mActive的值将被设置为true
mActive = newActive;
// 只要有活跃观察者,也就是组件的状态是START或RESUME时mActiveCount就不等于0,wasInactive为true
boolean wasInactive = LiveData.this.mActiveCount == 0;
// mActiveCount大于0
LiveData.this.mActiveCount += mActive ? 1 : -1;
// wasInactive和mActive都为true,执行
if (wasInactive && mActive) {
onActive();
}
// mActiveCount大于0 ,fasle && false,不执行
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
// mActive为true
if (mActive) {
//分发处理ObserverWrapper,也就是添加进去的观察者LifecycleBoundObserver
dispatchingValue(this);
}
}
看到这里至少就可以解释为什么在 PagedList 初始加载数据时会回调 onChanged 方法,而在加载下一页数据时不再回调 onChanged 方法了,
继续查看 LiveData 的方法 dispatchingValue 方法,源码如下:
// dispatchingValue方法
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// ...
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
// 遍历获取Observer处理
considerNotify(iterator.next().getValue());
//...
}
// ...
}
// considerNotify方法
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
// 观察者不处于活跃状态,不通知观察者
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 通知观察者
observer.mObserver.onChanged((T) mData);
}
至此,将结果回调给具体的观察者。
从 mPagedList 的创建开始,创建 mPagedList 代码如下:
// LiveData
private LiveData<PagedList<DataBean.ResultsBean>> mPagedList = new LivePagedListBuilder<>(factory,config)
.build();
继续查看关键方法 build,源代码如下:
// build方法
public LiveData<PagedList<Value>> build() {
return create(mInitialLoadKey, mConfig, mBoundaryCallback, mDataSourceFactory,
ArchTaskExecutor.getMainThreadExecutor(), mFetchExecutor);
}
// create方法
private static <Key, Value> LiveData<PagedList<Value>> create(
return new ComputableLiveData<PagedList<Value>>(fetchExecutor) {
@Nullable
private PagedList<Value> mList;
@Nullable
private DataSource<Key, Value> mDataSource;
// DataSource失效回调
private final DataSource.InvalidatedCallback mCallback =
new DataSource.InvalidatedCallback() {
@Override
public void onInvalidated() {
// 回调该方法通常表示需要新的数据源
invalidate();
}
};
@SuppressWarnings("unchecked") // for casting getLastKey to Key
@Override
protected PagedList<Value> compute() {
@Nullable Key initializeKey = initialLoadKey;
if (mList != null) {
initializeKey = (Key) mList.getLastKey();
}
do {
if (mDataSource != null) {
mDataSource.removeInvalidatedCallback(mCallback);
}
mDataSource = dataSourceFactory.create();
mDataSource.addInvalidatedCallback(mCallback);
// 创建PagedList,PageList是如何创建存储的且看下文
mList = new PagedList.Builder<>(mDataSource, config)
.setNotifyExecutor(notifyExecutor)
.setFetchExecutor(fetchExecutor)
.setBoundaryCallback(boundaryCallback)
.setInitialKey(initializeKey)
.build();
} while (mList.isDetached());//DataSource无效时,还是使用以前的数据,DataSource有效是执行一次返回PagedList
return mList;
}
}.getLiveData();
}
使用 getLiveData 获取 LiveData 数据,其中 LiveData 数据的更新是在一个名为 mRefreshRunnable 的 Ruuable 中更新的,在 mRefreshRunnable 中会调用上面的 compute 方法生成 PagedList,然后使用 LiveData 的 postValue 方法更新 PageList 数据到 LiveData 中,源码如下:
final Runnable mRefreshRunnable = new Runnable() {
// ...
try {
T value = null;
while (mInvalid.compareAndSet(true, false)) {
computed = true;
// 生成PagedList
value = compute();
}
if (computed) {
// 更新LiveData
mLiveData.postValue(value);
}
} finally {
// release compute lock
mComputing.set(false);
}
// ...
};
到此为止,LiveData<PagedList> 从创建到更新就分析完了。
接着上文继续看一下 PagedList 是如何生成的,PagedList 创建的关键源码如下:
// PagedList的创建
mList = new PagedList.Builder<>(mDataSource, config)
.setNotifyExecutor(notifyExecutor)
.setFetchExecutor(fetchExecutor)
.setBoundaryCallback(boundaryCallback)
.setInitialKey(initializeKey)
.build();
// 继续查看build方法,调用了PagedList的create方法
public PagedList<Value> build() {
// ...
return PagedList.create(
mDataSource,
mNotifyExecutor,
mFetchExecutor,
mBoundaryCallback,
mConfig,
mInitialKey);
}
// 真正创建PagedList
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) {
// PageKeyedDataSource继承ContiguousDataSource,dataSource.isContiguous()为true
if (dataSource.isContiguous() || !config.enablePlaceholders) {
int lastLoad = ContiguousPagedList.LAST_LOAD_UNSPECIFIED;
// 使用PageKeyedDataSource不会执行
if (!dataSource.isContiguous()) {
//noinspection unchecked
dataSource = (DataSource<K, T>) ((PositionalDataSource<T>) dataSource)
.wrapAsContiguousWithoutPlaceholders();
if (key != null) {
lastLoad = (Integer) key;
}
}
// 创建并返回ContiguousPagedList,也就是PagedList
ContiguousDataSource<K, T> contigDataSource = (ContiguousDataSource<K, T>) dataSource;
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.dispatchLoadInitial(key,
mConfig.initialLoadSizeHint,
mConfig.pageSize,
mConfig.enablePlaceholders,
mMainThreadExecutor,
mReceiver);
// ...
}
这里调用了抽象类 ContiguousDataSource 的 dispatchLoadInitial 方法,查看各类具体的实现类 PageKeyedDataSource 里面实现的具体的 dispatchLoadInitial 方法,源码如下:
@Override
final void dispatchLoadInitial(@Nullable Key key, int initialLoadSize, int pageSize,
boolean enablePlaceholders, @NonNull Executor mainThreadExecutor,
@NonNull PageResult.Receiver<Value> receiver) {
// 创建了LoadInitialCallback,也就是自定义DataSource中回调从网络加载数据时使用的callback
LoadInitialCallbackImpl<Key, Value> callback =
new LoadInitialCallbackImpl<>(this, enablePlaceholders, receiver);
// 自定义DataSource需要实现的loadInitial方法,在这里完成回调
loadInitial(new LoadInitialParams<Key>(initialLoadSize, enablePlaceholders), callback);
// 设置callback的回调执行在主线程
callback.mCallbackHelper.setPostExecutor(mainThreadExecutor);
}
到此为止,还不知道回调过去的数据时怎么保存的,所以继续查看 callback 的具体实现及回调,源码如下:
static class LoadInitialCallbackImpl<Key, Value> extends LoadInitialCallback<Key, Value> {
final LoadCallbackHelper<Value> mCallbackHelper;
private final PageKeyedDataSource<Key, Value> mDataSource;
private final boolean mCountingEnabled;
// LoadInitialCallbackImpl构造方法
LoadInitialCallbackImpl(@NonNull PageKeyedDataSource<Key, Value> dataSource,
boolean countingEnabled, @NonNull PageResult.Receiver<Value> receiver) {
// 这里需记住ResultType为PageResult.INIT,也就是初始加载数据时候数据的类型,后文中遇到PageResult.INIT
mCallbackHelper = new LoadCallbackHelper<>(
dataSource, PageResult.INIT, null, receiver);
mDataSource = dataSource;
mCountingEnabled = countingEnabled;
}
// 这个onResult回调显然不是PageKeyedDataSource设置数据时使用,应该是使用PositionalDataSource使用的,这里略过
@Override
public void onResult(@NonNull List<Value> data, int position, int totalCount,
@Nullable Key previousPageKey, @Nullable Key nextPageKey) {
if (!mCallbackHelper.dispatchInvalidResultIfInvalid()) {
LoadCallbackHelper.validateInitialLoadParams(data, position, totalCount);
// setup keys before dispatching data, so guaranteed to be ready
mDataSource.initKeys(previousPageKey, nextPageKey);
int trailingUnloadedCount = totalCount - position - data.size();
if (mCountingEnabled) {
mCallbackHelper.dispatchResultToReceiver(new PageResult<>(
data, position, trailingUnloadedCount, 0));
} else {
mCallbackHelper.dispatchResultToReceiver(new PageResult<>(data, position));
}
}
}
// 这个onResult回调是PageKeyedDataSource设置数据时使用的
@Override
public void onResult(@NonNull List<Value> data, @Nullable Key previousPageKey,
@Nullable Key nextPageKey) {
// DataSource有效时dispatchInvalidResultIfInvalid返回false
if (!mCallbackHelper.dispatchInvalidResultIfInvalid()) {
// 初始化在loadInitial中设置的previousPageKey, nextPageKey,应该是用来区分加载上一页还是加载下一页
mDataSource.initKeys(previousPageKey, nextPageKey);
// 分发回调过来的数据data
mCallbackHelper.dispatchResultToReceiver(new PageResult<>(data, 0, 0, 0));
}
}
}
这里已经拿到了从网络加载的数据,继续查看 dispatchResultToReceiver 方法,看数据时如何被处理的,其源码如下:
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;
}
// 如果executor为null,因为在上面的分析中,这里的回调executor被赋值并运行在主线程
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
// 数据继续回调
mReceiver.onPageResult(mResultType, result);
}
});
} else {// 非主线程直接回调
mReceiver.onPageResult(mResultType, result);
}
}
这里继续查看 onPageResult 的具体实现,查看源码知这个过程在 ContiguousPagedList 中实现,其源码具体如下:
PageResult.Receiver<V> mReceiver = new PageResult.Receiver<V>() {
@AnyThread
@Override
public void onPageResult(@PageResult.ResultType int resultType,
@NonNull PageResult<V> pageResult) {
// ...
List<V> page = pageResult.page;
// 前面在初始化加载数据,创建LoadCallbackHelper时,数据状态是PageResult.INIT
// 也就是初始化调用loadInitial的时候
if (resultType == PageResult.INIT) {
// 1.保存数据到PagedStorage
// 2.最终调用RecyclerView.Adapte的notifyItemRangeInserted(position, count)方法,position为0
mStorage.init(pageResult.leadingNulls, page, pageResult.trailingNulls,
pageResult.positionOffset, ContiguousPagedList.this);
// ...
} else {
// ...
// 创建LoadCallbackHelper时,数据状态是PageResult.APPEND
// 也就是调用loadAfter的时候
if (resultType == PageResult.APPEND) {
if (skipNewPage && !trimFromFront) {
// don't append this data, drop it
mAppendItemsRequested = 0;
mAppendWorkerState = READY_TO_FETCH;
} else {
// 1.保存数据到PagedStorage
// 2.最终回调loadAfter
mStorage.appendPage(page, ContiguousPagedList.this);
}
// 创建LoadCallbackHelper时,数据状态是PageResult.PREPEND
// 也就是调用loadBefore的时候
} else if (resultType == PageResult.PREPEND) {
if (skipNewPage && trimFromFront) {
// don't append this data, drop it
mPrependItemsRequested = 0;
mPrependWorkerState = READY_TO_FETCH;
} else {
// 1.保存数据到PagedStorage
// 2.最终回调loadBefore
mStorage.prependPage(page, ContiguousPagedList.this);
}
} else {
throw new IllegalArgumentException("unexpected resultType " + resultType);
}
// ...
}
};
到此 PagedList 的创建以及保存过程就结束了,之前从 observer 开始分析了 PagedList 的数据回调,会调用 onChanged 方法,在该方法里面为 RecyclerVIew 的 Adaptyer 设置数据,代码如下:
mViewModel.getPagedList().observe(this, new Observer<PagedList<DataBean.ResultsBean>>() {
@Override
public void onChanged(PagedList<DataBean.ResultsBean> dataBeans) {
// 设置要显示的数据,只会在初始化的时候回调一次
// 如果已经有显示列表,则会在后台线程中计算数据差异,并通知数据更新
mAdapter.submitList(dataBeans);
}
});
上面提到如果以及存在显示列表,则会在后台线程中计算数据差异并通知数据更新,那么这个后台线程在哪呢,mAdapter 的 submitList 方法最终调用下面的 submitList 方法,里面通过 AsyncDifferConfig 获取后台线程执行数据的差异计算,这个后台线程池如果不指定则是一个固定大小为 2 的线程池,源码如下:
@SuppressWarnings("ReferenceEquality")
public void submitList(@Nullable final PagedList<T> pagedList,
@Nullable final Runnable commitCallback) {
// ...
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());
// 将计算结果回调到主线程,然后通知数据集更新,进而通知RecyclerView更新数据
mMainThreadExecutor.execute(new Runnable() {
@Override
public void run() {
if (mMaxScheduledGeneration == runGeneration) {
latchPagedList(pagedList, newSnapshot, result,
oldSnapshot.mLastLoad, commitCallback);
}
}
});
}
});
}
继续查看 latchPagedList 源码,这里将会进行数据的更新操作以及读取数据,其源码如下:
void latchPagedList(
@NonNull PagedList<T> newList,
@NonNull PagedList<T> diffSnapshot,
@NonNull DiffUtil.DiffResult diffResult,
int lastAccessIndex,
@Nullable Runnable commitCallback) {
// ...
// 更新mPageList并通知RecyclerView更新数据
PagedStorageDiffHelper.dispatchDiff(mUpdateCallback,
previousSnapshot.mStorage, newList.mStorage, diffResult);
newList.addWeakCallback(diffSnapshot, mPagedListCallback);
if (!mPagedList.isEmpty()) {
// 读取数据
mPagedList.loadAround(Math.max(0, Math.min(mPagedList.size() - 1, newPosition)));
}
onCurrentListChanged(previousSnapshot, mPagedList, commitCallback);
}
其中 dispatchDiff 方法最终会调用 dispatchLastEvent 方法,源码如下:
public void dispatchLastEvent() {
if (mLastEventType == TYPE_NONE) {
return;
}
switch (mLastEventType) {
case TYPE_ADD:
mWrapped.onInserted(mLastEventPosition, mLastEventCount);
break;
case TYPE_REMOVE:
mWrapped.onRemoved(mLastEventPosition, mLastEventCount);
break;
case TYPE_CHANGE:
mWrapped.onChanged(mLastEventPosition, mLastEventCount, mLastEventPayload);
break;
}
mLastEventPayload = null;
mLastEventType = TYPE_NONE;
}
mWrapped 是一个 ListUpdateCallback,而 AdapterListUpdateCallback 实现了该接口,并在里面通知 RectclerView 的 Adapter 进行数据更新。
其中在 latchPagedList 方法中会调用 PagedList 的 loadAround 方法来获取数据,也就是使用在使用 PageKeyedDataSource 的时候实现的 loadBefore 和 loadAfter 方法,这里就不贴源码了。
Page Library 的分页加载流程就分析完了,看源码至少知道了 onChanged 方法只在初始化的时候只回调过一次,但是却能够不断加载下一页数据的原因。