Android loders异步加载框架
Loader基本介绍
- Loader:是一个执行异步数据加载的抽象类。它是AsyncTaskLoader的父类,CursorLoader的祖父类。
- AsyncTaskLoader:它是继承于Loader的抽象类。在AsyncTaskLoader中有AsyncTask用来执行异步工作。
- CursorLoader:它是AsyncTaskLoader的子类。它可以查询ContentResolver然后返回一个Cursor,同时CursorLoader内包含ContentObserver对象来监听Cursor数据的变化。
- LoaderManager:它是一个抽像类,作用是用来管理Loader。LoaderManager关联到一个Activity或Fragment;例如,在Activity中通过getLoaderManager()可以获取到一个LoaderManager对象。
- LoaderManager.LoaderCallbacks:它提供了与"Activity或Fragment"交互的接口。LoaderCallbacks中共包行三个接口:
- onCreateLoader():根据所给出的ID,初始化并返回一个新的加载器。
- onLoadFinished():当一个先前被创建的加载器完成了它的加载过程时被调用。
- onLoaderReset():当一个先前被创建的加载器被重置时被调用,然后使加载器的数据无效。
总结:Loader, AsyncTaskLoader和CursorLoader都是用来提供异步加载的类;而LoaderManager则提供了管理这些异步加载类的接口。此外,Activity或Fragment保护了获取LoaderManager的接口,通过这样的接口,就可以在Activity或Fragment中实现异步加载任务!
基本使用
启动装载器
通常要在Activity的onCreate()方法中或Fragment的onActivityCreated()方法中初始化一个装载器:
getLoaderManager().initLoader(0, null, this);
- id:一个唯一的ID用于标识这个装载器,同一个id的装载器可以做到重复利用;
- args:可选的参数,在装载器初始化时作为参数传入;参数经过流转,最终会传到
onCreateLoader(int id, Bundle args)
里 - callbacks:一个LoaderManager.LoaderCallbacks的实现,被LoaderManager调用以报告装载器事件;
源码分析
public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
LoaderInfo info = mLoaders.get(id);
if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
if (info == null) {
// Loader doesn't already exist; create.
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
if (DEBUG) Log.v(TAG, " Created new loader " + info);
} else {
if (DEBUG) Log.v(TAG, " Re-using existing loader " + info);
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
if (info.mHaveData && mStarted) {
// If the loader has already generated its data, report it now.
info.callOnLoadFinished(info.mLoader, info.mData);
}
return (Loader<D>)info.mLoader;
}
主要是两件事情:
- 根据传入的id,查询到对应的
LoaderInfo
数据; - 如果查询的数据为空,表示装载器未创建,则需要创建装载器;
- 如果查询的数据不为空,则只是更新下callback,然后直接调用onLoadFinished()。
下面是loadFinished的代码逻辑:
void callOnLoadFinished(Loader<Object> loader, Object data) {
if (mCallbacks != null) {
String lastBecause = null;
if (mHost != null) {
lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
}
try {
if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": "
+ loader.dataToString(data));
mCallbacks.onLoadFinished(loader, data);
} finally {
if (mHost != null) {
mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
mDeliveredData = true;
}
}
如果没有创建,则需要创建。
创建的逻辑
private LoaderInfo createAndInstallLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
try {
mCreatingLoader = true;
LoaderInfo info = createLoader(id, args, callback);
installLoader(info);
return info;
} finally {
mCreatingLoader = false;
}
}
private LoaderInfo createLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
LoaderInfo info = new LoaderInfo(id, args, callback);
Loader<Object> loader = callback.onCreateLoader(id, args);
info.mLoader = loader;
return info;
}
void installLoader(LoaderInfo info) {
mLoaders.put(info.mId, info);
if (mStarted) {
// The activity will start all existing loaders in it's onStart(),
// so only start them here if we're past that point of the activity's
// life cycle
info.start();
}
}
下面进入到LoaderManager.LoaderInfo里面:
void start() {
if (mRetaining && mRetainingStarted) {
// Our owner is started, but we were being retained from a
// previous instance in the started state... so there is really
// nothing to do here, since the loaders are still started.
mStarted = true;
return;
}
if (mStarted) {
// If loader already started, don't restart.
return;
}
mStarted = true;
if (DEBUG) Log.v(TAG, " Starting: " + this);
if (mLoader == null && mCallbacks != null) {
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
if (mLoader != null) {
if (mLoader.getClass().isMemberClass()
&& !Modifier.isStatic(mLoader.getClass().getModifiers())) {
throw new IllegalArgumentException(
"Object returned from onCreateLoader must not be a non-static inner member class: "
+ mLoader);
}
if (!mListenerRegistered) {
mLoader.registerListener(mId, this);
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
mLoader.startLoading();
}
}
主要是3个功能:
- 注册完成的监听
- 注册取消的监听
- 触发加载
-> Loader.startLoading:
public final void startLoading() {
mStarted = true;
mReset = false;
mAbandoned = false;
onStartLoading();
}
protected void onStartLoading() {
}
而onStartLoading方法是给实际的集成者完成的,比如我这边自己实现的Loader类:
@Override
protected void onStartLoading() {
if (netBean != null) {
deliverResult(netBean);
} else {
forceLoad();
}
}
其中deliverResult()
和 forceLoad()
都是Loader
类里的方法。
public void deliverResult(D data) {
if (mListener != null) {
mListener.onLoadComplete(this, data);
}
}
public void forceLoad() {
onForceLoad();
}
protected void onForceLoad() {
}
其中onForceLoad
又AsyncTaskLoader
类实现,该类是基于AsyncTask实现的一个异步加载框架。
@Override
protected void onForceLoad() {
super.onForceLoad();
cancelLoad();
mTask = new LoadTask();
if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
executePendingTask();
}
异步加载器如下:
@Override
protected D doInBackground(Void... params) {
if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
try {
D data = AsyncTaskLoader.this.onLoadInBackground();
if (DEBUG) Log.v(TAG, this + " <<< doInBackground");
return data;
} catch (OperationCanceledException ex) {
if (!isCancelled()) {
throw ex;
}
if (DEBUG) Log.v(TAG, this + " <<< doInBackground (was canceled)", ex);
return null;
}
}
/* Runs on the UI thread */
@Override
protected void onPostExecute(D data) {
if (DEBUG) Log.v(TAG, this + " onPostExecute");
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
mDone.countDown();
}
}
/* Runs on the UI thread */
@Override
protected void onCancelled(D data) {
if (DEBUG) Log.v(TAG, this + " onCancelled");
try {
AsyncTaskLoader.this.dispatchOnCancelled(this, data);
} finally {
mDone.countDown();
}
}
onLoadInBackground
public abstract D loadInBackground(); protected D onLoadInBackground() { return loadInBackground(); }
上面的抽象类是需要子类实现的,如我的demo:
@Override public NetBean loadInBackground() { Log.e("111", "======================="); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } netBean = new NetBean(); return netBean; }
- dispatchOnLoadComplete
最终也是走到Loader的void dispatchOnLoadComplete(LoadTask task, D data) { if (mTask != task) { if (DEBUG) Log.v(TAG, "Load complete of old task, trying to cancel"); dispatchOnCancelled(task, data); } else { if (isAbandoned()) { // This cursor has been abandoned; just cancel the new data. onCanceled(data); } else { commitContentChanged(); mLastLoadCompleteTime = SystemClock.uptimeMillis(); mTask = null; if (DEBUG) Log.v(TAG, "Delivering result"); deliverResult(data); } } }
deliverResult()
方法。最终走到onLoadFinished(). dispatchOnCancelled
void dispatchOnCancelled(LoadTask task, D data) { onCanceled(data); if (mCancellingTask == task) { if (DEBUG) Log.v(TAG, "Cancelled task is now canceled!"); rollbackContentChanged(); mLastLoadCompleteTime = SystemClock.uptimeMillis(); mCancellingTask = null; if (DEBUG) Log.v(TAG, "Delivering cancellation"); deliverCancellation(); executePendingTask(); } } public void deliverCancellation() { if (mOnLoadCanceledListener != null) { mOnLoadCanceledListener.onLoadCanceled(this); } }
重启装载器
有的时候你却想丢弃旧的装载器然后开始一个新的装载器,要想丢弃旧的装载器,你应使用restartLoader()
。
重启装载器的实现,主要是先将老的装载器查询出来,释放掉所有的资源,然后重新创建。
LoaderManager.LoaderCallbacks
装载器的回调接口,实现应用层与LoaderManager的交互,主要是如下几个回调:
- onCreateLoader():根据传入的ID,初始化并返回一个新的装载器
- onLoadFinished():当一个装载器完成了它的装载过程后调用
- onLoaderReset():当一个装载器被重置,从而使得其数据无效时被调用
自定义Loader
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.pan.lean.photowall.loaders;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import android.util.Log;
/**
* Created by panhongchao on 17/3/20.
*/
public class NetworkLoader extends AsyncTaskLoader<NetBean> {
private NetBean netBean;
public NetworkLoader(Context context) {
super(context);
}
@Override
public NetBean loadInBackground() {
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("111", "loader loadInBackground is called");
netBean = new NetBean();
return netBean;
}
@Override
protected void onStartLoading() {
if (netBean != null) {
deliverResult(netBean);
} else {
forceLoad();
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
public void onCanceled(NetBean data) {
netBean = null;
}
}
Loader框架与AsyncTask
Loader框架最大的改进是异步的线程的加载跟Fragment/Activity的生命周期绑定上了,从而从根本上保证了内存泄漏的问题。
这是怎么实现的呢?
是通过将F/A的生命周期的每次回调都代理到了LoaderManager上。
以Destory为例: