Android-Loader-分析

Fragment和Acitity都有LoaderManager, 这次以app.content.Fragment的LoaderManager来分析,下面有关的源码是API 23的,先上张图:

通常在Fragment中onActiviytCreate()方法出初始化loader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  getLoaderMananger().initLoader(id, bundle, new LoaderManager.LoaderCallbacks<T>(){
@Override
public Loader<T> onCreateLoader(int id, Bundle args) {
//创建loader
return loader;
}

@Override
public void onLoadFinished(Loader<T> loader, T t) {
//处理loader完成后的数据
}

@Override
public void onLoaderReset(Loader<RESTResponse> loader) {

}
}
)

Loader初始化

LoaderManager的初始化的实现类是LoaderManagerImpl, 这里有个类似Map的SparseArrayCompat的成员变量, 它的Key是initLoader传进来的Id:

1
2
3
4
5
6
7
8
9
10
LoaderInfo info = mLoaders.get(id);
if (info == null) {
info = createAndInstallLoader(id, args,(LoaderManager.LoaderCallbacks<Object>)callback);
} else {
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}

if (info.mHaveData && mStarted) {
info.callOnLoadFinished(info.mLoader, info.mData);
}

上述是initLoader方法的主要代码, 先check一下是否存在这个id的LoaderInfo,
如果不存在就创建,否则将LoaderCallbacks赋值给LoaderInfo的成员变量mCallbacks. loaderInfo里有数据同时Fragment已经处于onStart状态,就回调到
LoaderCallbacks的onLoaderFinished方法.

LoaderInfo不存在, 会用id,bundle, LoaderCallbacks创建对象:

1
2
3
4
mLoaders.put(info.mId, info);
if (mStarted) {
info.start();
}

到这里initLoader完成。start()方法启动Loader任务,但mStarted跟Fragment的onstart()绑定, 也就是说不管你在Fragment的onCreateView, onActiviytCreate等方法调用initloader初始化loader没有本质的不同,真正开始loader任务要在Fragment的onstart之后

Loader的启动

在Fragment的onStart()里:

1
2
3
if (mLoaderManager != null) {
mLoaderManager.doStart();
}

在LoaderManagerImpl的doStart()启动所有loader

1
2
3
4
5
mStarted = true;

for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).start();
}

LoaderInfo的LoaderCallbacks回调创建Loader对象,
LoaderInfo实现了Loader的Finished和Canceled监听, 将监听注册到Loader并启动任务

1
2
3
4
5
6
7
8
9
10
if (mLoader == null && mCallbacks != null) {
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
...
if (!mListenerRegistered) {
mLoader.registerListener(mId, this);
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
mLoader.startLoading();

Loader数据回调

数据回调用LoaderInfo实现Loader的LoadComplete(Loader loader, Object data)
1
2
3
4
5
6
7
if (mData != data || !mHaveData) {
mData = data;
mHaveData = true;
if (mStarted) {
callOnLoadFinished(loader, data);//回调mCallbacks.onLoadFinished(loader, data);
}
}

Loader停止

当Fragment走onStop后

1
2
3
4
5
6
7
if (mLoaderManager != null) {
if (mRetaining) {
mLoaderManager.doRetain();//据说这里有bug,有些不同版本API保存不了状态, 打算跳过
} else {
mLoaderManager.doStop();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).stop();
}
mStarted = false;

//LoaderInfo的stop(), 注销Loader的监听,并停止
if (!mRetaining) {
if (mLoader != null && mListenerRegistered) {
mListenerRegistered = false;
mLoader.unregisterListener(this);
mLoader.unregisterOnLoadCanceledListener(this);
mLoader.stopLoading();
}
}

Loader的销毁

当Fragment走onDestroy,最终也是遍历所有LoaderInfo的destroy():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
boolean needReset = mDeliveredData;

if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
mCallbacks.onLoaderReset(mLoader);//mDeliveredData = true才会回调callback的reset,也就是说必须先有callback有数据回调
}
...
if (mLoader != null) {
if (mListenerRegistered) {
mListenerRegistered = false;
mLoader.unregisterListener(this);
mLoader.unregisterOnLoadCanceledListener(this);
}
mLoader.reset();
}

销毁某个Loader

getLoaderMananger().destroyLoader(int id)的方法就很清晰了,查找这个id的Loader,从Loaders中remove 并 destroy掉

1
2
3
4
5
6
int idx = mLoaders.indexOfKey(id);
if (idx >= 0) {
LoaderInfo info = mLoaders.valueAt(idx);
mLoaders.removeAt(idx);
info.destroy();
}

重新启动某个Loader

getLoaderMananger().restartLoader(id, bundle, LoaderManager.LoaderCallbacks)就相对复杂点,如果这个id的Loader不存在,就创建;
如果存在,就有三种情况:

  • Loader还没启动;
  • Loader启动了,数据还在Loading;
  • Loader启动了,数据Loading好了;
    具体代码就不贴上了,比较多
Loading comments box needs to over the wall