前言
Loader是Android3.0之后自带的异步请求框架,集成到了Activity和Fragment中,实现和Activity生命周期联动效果,而且它还可以监听数据源,如果数据源发生了变化能够接收到通知。除此之外Loader还能够缓存后台请求到的数据,等到界面切换到前台再更新界面,避免重复的网路请求。
Loader源码
先看Loader里定义的成员变量,主要有id,context、监听器和一些状态标记。
public class Loader<D> { // 泛型D就是加载的数据类型
// loader的id,每一个Activity/Fragment一个id只对应一个loader
int mId;
// 当数据加载完成时的回调监听器
OnLoadCompleteListener<D> mListener;
// 当取消当前数据加载时的回调加载监听器
OnLoadCanceledListener<D> mOnLoadCanceledListener;
// Context对象,保存的是ApplicationContext,不会保存Activity
Context mContext;
// 当前loader是否处于start状态,只有在onStart和onStop之间才会是mStarted = true;
boolean mStarted = false;
// 当前loader是否已经被抛弃,如果restartLoader使用相同的id,会新建一个loader,当前已存在的loader就会被抛弃,不过当前loader处于什么状态
boolean mAbandoned = false;
// loader是否被重置
boolean mReset = true;
// 在loader mStarted=false,也就是loader处于后台,这时候数据源的数据是否发生变化
boolean mContentChanged = false;
// 目前loader是否处于正在处理数据源变化的过程中,处理过程是需要花费时间的,在这段时间可能需要刷新UI界面
boolean mProcessingChange = false;
接下来看到的就是loader的回调监听器,第一个是数据源观察者实现类:
public final class ForceLoadContentObserver extends ContentObserver {
public ForceLoadContentObserver() {
super(new Handler());
}
@Override
public boolean deliverSelfNotifications() {
return true;
}
// 在数据源发生变化的时候回调loader的onContentChanged方法
@Override
public void onChange(boolean selfChange) {
onContentChanged();
}
}
接下来的两个接口定义了当loader加载到数据和取消加载数据的回调接口:
public interface OnLoadCompleteListener<D> {
// 当数据请求成功回调此接口
public void onLoadComplete(Loader<D> loader, D data);
}
public interface OnLoadCanceledListener<D> {
// 当数据请求未完成,请求取消数据加载
public void onLoadCanceled(Loader<D> loader);
}
这两个接口都是Android的Loader Framework调用的,使用loader的用户不用自己实现它们。
public Loader(Context context) {
mContext = context.getApplicationContext();
}
// 发送加载的数据到LoadComplete接口,只应该在loader的子类中调用,必须要在主线程里调用
public void deliverResult(D data) {
if (mListener != null) {
mListener.onLoadComplete(this, data);
}
}
// 发送取消加载到LoadComplete接口,只应该在loader的子类中调用,必须要在主线程里调用
public void deliverCancellation() {
if (mOnLoadCanceledListener != null) {
mOnLoadCanceledListener.onLoadCanceled(this);
}
}
够着方法里只是保存下了ApplicationContext的引用,deliveryResult和deliveryCancellation负责回调注册的接口,并且只能在实际实现的loader子类里调用。接下来的代码都是负责注册和注销监听器,还有状态变量的get方法,没有什么值得看得。
下面会接触到加载数据的loader接口,startLoading和onStartLoading:
// 开始异步加载数据,这个方法是loaderManager框架负责调用的,用户不用手动调用
public final void startLoading() {
mStarted = true;
mReset = false;
mAbandoned = false;
onStartLoading();
}
// 子类负责实现具体的加载任务
protected void onStartLoading() {
}
这里面用在startLoading里调用了onStartLoading钩子函数,这样当子类在onStartLoading里做网络请求或者本地磁盘读取操作就能被loadManager框架回调了。其中的mStarted代表当前的界面处于前台并且开始加载异步数据。
接下来的cancelLoad和onCancelLoad和前面的实现类似,只不过它们负责取消当前正在执行的异步加载。
// 取消加载操作是一个耗时的任务,无法立即完成,所以如果当前的异步加载正在执行则需要等到执行完成在清空它的状态,如果现在有一个新相同id的异步加载这个加载会被暂停知道前一个完全被取消。
public boolean cancelLoad() {
return onCancelLoad();
}
protected boolean onCancelLoad() {
return false;
}
forceLoad加载和startLoad不同点在于对缓存中已存在的数据处理不同,如果startLoading请求发现缓存有数据就会直接回调onLoadComplete,而forceLoad会忽略缓存中的数据,直接发送请求
。
public void forceLoad() {
onForceLoad();
}
protected void onForceLoad() {
}
stopLoading停止当前的加载,其实不会停止后台线程的执行,只是即使后台执行完成也无法回调onLoadComplete方法,该方法也是loaderManager框架回调,不需要使用者自己调用。
public void stopLoading() {
mStarted = false;
onStopLoading();
}
protected void onStopLoading() {
}
abandon和reset方法都只是对loader的状态进行更新,使得其中的数据不会被发送到主线程。
public void abandon() {
mAbandoned = true;
onAbandon();
}
protected void onAbandon() {
}
public void reset() {
onReset();
mReset = true;
mStarted = false;
mAbandoned = false;
mContentChanged = false;
mProcessingChange = false;
}
protected void onReset() {
}
最后的几个方法是关于loader数据源发生改变时,处理相关业务的接口:
// 获取后台数据是否已改变,当mContentChange或者mProcessingChange其中一个为true表示后台数据发生了变化
public boolean takeContentChanged() {
boolean res = mContentChanged;
mContentChanged = false;
mProcessingChange |= res;
return res;
}
// 提交后台数据改变的事务,本次侦测到数据源改变已全部执行完成
public void commitContentChanged() {
mProcessingChange = false;
}
// 回滚数据源改变的事务,并且如果事务正在执行就重新触发onContentChange
public void rollbackContentChanged() {
if (mProcessingChange) {
onContentChanged();
}
}
// 当 ForceLoadContentObserver发现数据源发生改变,首先检查当前loader是否处于前台,如果是就直接强制重新请求新数据,否则就记录下数据源发生改变
public void onContentChanged() {
if (mStarted) {
forceLoad();
} else {
mContentChanged = true;
}
}
AsyncTask源码
AsyncTask封装了Handler和Executor实现异步加载,使用起来非常简单,目前的execute方法使用的是串行执行方式,但是可以调用executeOnExecutor多个任务并行执行。从AsyncTask的声明可以看出它是一个抽象类,必须实现之类,它使用了三个泛型类分别代表请求参数、加载进度和请求数据类型。
public abstract class AsyncTask<Params, Progress, Result> {
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
// 并行执行器
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
// 串行执行器
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
如果对Executor框架熟悉的话就知道这段代码是在初始化异步执行的线程池,线程池中核心线程最少2个最多4个,否则就是CPU数量减1个;最大线程数是CPU数*2+1个,注意到workQueue是一个有界最多存放128个任务的连表阻塞队列。如果线程池里的线程数少于核心线程数添加新任务就会直接创建一个新的Thread负责执行,这些核心线程不会在任务完成后就释放,而是会一直存在。如果执行器里的线程数量达到了核心线程数量而且没有空闲线程,那么新加入的任务会被放到workQueue中,也就是说workQueue最多放128个任务,如果workQueue满了,再放入新的任务这时如果执行器线程未达到最大线程数,就新建线程然后执行任务,执行完任务之后如果在30秒内没有发现有任务就会销毁。如果最大线程数也达到了就会执行拒绝策略,通常是抛出异常。
最后一行新建了一个串行执行器,它能够对加入的任务执行串行化,在前一个任务执行完成之后在开始下一个任务的执行。具体实现代码如下:
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() { // 将新提交的任务封装之后加入任务队列中
public void run() {
try {
r.run(); // 执行当前任务
} finally {
scheduleNext(); // 当前任务结束之后,从工作队列中取出后一个任务继续执行
}
}
});
if (mActive == null) {
scheduleNext(); // 第一次提交任务或者以前的任务全部执行完成,直接执行本次新加入的任务
} // 否则什么都不做,mActivite执行完后续会调度
}
// 在并行执行器里执行工作队列里下一个任务
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
查看一下AsyncTask里面的其他成员属性:
// 向主线程发布已成功加载数据的消息
private static final int MESSAGE_POST_RESULT = 0x1;
// 向主线程发布加载数据进度的消息
private static final int MESSAGE_POST_PROGRESS = 0x2;
// 定义默认的执行器是串行执行器
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
// 负责在主线程和子线程之间传递消息的Handler
private static InternalHandler sHandler;
// 定义负责实际执行加载操作的工作类,执行器会执行的它的call()方法
private final WorkerRunnable<Params, Result> mWorker;
// 包含实际加载数据的Future对象,执行器加载数据完成之后或请求被取消会回调它的done()方法
private final FutureTask<Result> mFuture;
// 当前异步任务对象的执行状态,是Peding挂起状态,还有Running运行状态,Finished结束状态
private volatile Status mStatus = Status.PENDING;
// 当前异步任务是否被取消
private final AtomicBoolean mCancelled = new AtomicBoolean();
// 当前异步任务是否已经开始
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
// 用来负责当前线程和数据需要发送到的线程通信的Handler,通常都是主线程的Handler
private final Handler mHandler;
成员变量定义完成之后看下构造函数里是如何初始化的它们,这里只初始化了mWorker和mFuture两个对象。需要注意的是mFuture的done()方法不管是任务正常还是被取消都会被执行。
public AsyncTask(@Nullable Looper callbackLooper) {
// 定义交互加载线程和需要数据的线程(通常都是主线程)交互Handler
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
// 定义工作者对象需要做的任务
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true); // 如果开始执行就设置任务被调用
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//调用doInBackground方法,同时传入请求参数Params,该方法返回的类型正是Result类型
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true); // 如果出现异常,就当作当前任务被取消
throw tr;
} finally {
// 将请求到的数据发送到主线程
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
// 如果在任务结束或者任务被取消
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
private void postResultIfNotInvoked(Result result) {
// Result通常都是空对象null
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result); // 如果任务还未开始就被取消,发送null对象到主线程
}
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
// 发送真正请求到的数据到主线程,
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
发送的数据实体类包含当前Task对象和请求到的数据,之所以将任务对象也抛到主线程中是因为任务对象里面有用户自定义的在主线程里的回调操作onProgressUpdate和onPostExecute方法。
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
发送到主线程数据和任务对象是如何处理的呢,查看一下InternalHandler的实现代码:
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// 主线程接收到发送过来的结果对象,回调Finished方法
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
// 如果主线程收到发送过来的进度通知,调用onProgressUpdate方法,publishProgress方法需要在doInBackground方法里调用。
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
// Finish方法在接收到请求结果如果当前异步加载已被取消,那就执行onCancel,否则执行onPostExecute方法,同时标记当前异步任务结束状态
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
AsyncTask内部执行逻辑已经分析完了,用户通常调用接口是execute方法,这个方法最后会调用executeOnExcutor方法,在它内部会首先调用onPreExecute,这也就是为什么AsyncTask必须要在主线程中执行的原因,之后开始异步启动线程执行mFuture的run方法,run方法里面又调用的mWorker对象的call方法,从而执行了doInBackground里用户自定义的请求。
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
// 执行是任务状态必须是挂起PEDING状态,如果不是就会抛出异常,这也就是为什么AsyncTask只能被执行一次,因为只要执行过它的状态不是RUNNING运行状态就是FINISHED结束状态。
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
最后在来看一下AsyncTask的取消操作,有时候用户没有等到任务请求返回就推出了界面,这时后就没有必要在继续后续操作了,所以cancel操作也是一个重要的功能。
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
实现很简短就是设置一个取消的标记,同时mFuture对象cancel当前的任务,查看FutureTask源码可以看到实际执行的是Thead.interrupt方法,但是线程会继续执行下去,只不过回调异步任务的onCancle方法。其他的publishProgress实现和postResult实现原理基本一致,不再详述。
AsyncTaskLoader源码
AsyncTaskLoader继承自Loader但是底层的异步请求实现却是AsyncTask,了解了异步任务的实现逻辑,再阅读AsyncTaskLoader就会轻松很多。最开始定义了一个异步任务类,它的实现代码如下:
final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
// 计数器同步器,测试使用不必关心
private final CountDownLatch mDone = new CountDownLatch(1);
// 当异步任务执行doInBackground的时候实际执行的是AsyncTaskLoader的onLoadInBackground方法
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;
}
}
// 当异步任务执行完成回调会执行loaderd的disptachOnLoadComplete方法,并将同步计数器置零
protected void onPostExecute(D data) {
if (DEBUG) Log.v(TAG, this + " onPostExecute");
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
mDone.countDown();
}
}
// 当异步任务被取消时执行loader的dispatchOnCancelled方法,并将同步计数器置零
protected void onCancelled(D data) {
if (DEBUG) Log.v(TAG, this + " onCancelled");
try {
AsyncTaskLoader.this.dispatchOnCancelled(this, data);
} finally {
mDone.countDown();
}
}
// 实现Runnable接口,如果在线程里执行当前异步对象,就会执行loader的executePendingTask方法
public void run() {
waiting = false;
AsyncTaskLoader.this.executePendingTask();
}
}
可见LoadTask类只是对AsyncTask异步任务类的简单封装,将后台加载、请求成功和请求取消回调都放到AsyncTaskLoader里来实现。
AsyncTaskLoader的成员对象很少,只有5个成员变量
// 执行器对象,默认是异步任务的并行执行器
private final Executor mExecutor;
// 当前执行异步任务对象
volatile LoadTask mTask;
// 正在被取消的异步任务对象
volatile LoadTask mCancellingTask;
// 节流相关,一般未配置,如果设置了要求下一次请求距离上一次请求完成要超过mUpdateThrottle这么长时间才会执行下一次请求,通常不会使用,这里也不再讨论
long mUpdateThrottle;
long mLastLoadCompleteTime = -10000;
Handler mHandler; // 主线程通信Handler对象,负责处理节流的延迟处理
public AsyncTaskLoader(Context context) {
this(context, AsyncTask.THREAD_POOL_EXECUTOR);
}
public AsyncTaskLoader(Context context, Executor executor) {
super(context);
mExecutor = executor;
}
接下来看两个最重要的方法,开始异步请求和取消异步请求。
@Override
protected void onForceLoad() {
super.onForceLoad();
// 首先取消目前正在进行的异步任务请求,实际上调用的就是onCancelLoad方法
cancelLoad();
// 新建即将开始的新任务
mTask = new LoadTask();
if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
// 执行挂起的任务
executePendingTask();
}
@Override
protected boolean onCancelLoad() {
// 如果当前有任务正在执行
if (mTask != null) {
if (!mStarted) { // 如果界面为在最前方,只记录内容已更改
mContentChanged = true;
}
if (mCancellingTask != null) { // 如果目前有一个任务正在被取消
if (mTask.waiting) { // 当前任务因为节流被延迟回调,取消延迟回调
mTask.waiting = false;
mHandler.removeCallbacks(mTask);
}
// 当前任务还未开始,只要清空当前任务既可
mTask = null;
return false;
} else if (mTask.waiting) { // 如果当前任务因节流被延迟回调,也就是还未开始,取消延迟回调
mTask.waiting = false;
mHandler.removeCallbacks(mTask);
// 当前任务还未开始,只要清空当前任务既可
mTask = null;
return false;
} else {
// 如果当前任务正在被执行,取消当前任务
boolean cancelled = mTask.cancel(false);
// 记录当前任务为正在取消的任务,并清空当前任务
if (cancelled) {
mCancellingTask = mTask;
cancelLoadInBackground();
}
mTask = null;
return cancelled;
}
}
return false;
}
可见发起新的异步请求还要考虑loader里之前发起的异步请求,只有之前的任务被彻底取消才会开始当前任务,executePendingTask方法实现:
void executePendingTask() {
// 如果当前没有正在取消的任务而且当前任务不为空
if (mCancellingTask == null && mTask != null) {
if (mTask.waiting) { // 如果当前任务被节流处理,先取消之前的延迟回调
mTask.waiting = false;
mHandler.removeCallbacks(mTask);
}
if (mUpdateThrottle > 0) { // 判断设置了节流时间
long now = SystemClock.uptimeMillis();
if (now < (mLastLoadCompleteTime+mUpdateThrottle)) {
// 当前时间距离上一次加载结束时间未超过了节流时间,延迟开始异步加载
mTask.waiting = true;
mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);
return;
}
}
// 没有节流时间设置,直接并发执行请求
mTask.executeOnExecutor(mExecutor, (Void[]) null);
}
// 如果当前有正在取消的任务或者当前任务为空,什么都不做
}
最后两个方法都是AsyncTask里回调的方法,一个是成功的回调一个是取消的回调。
// 如果正在被取消任务取消完成,置空mCancellingTask,并且执行executePedingTask,开始执行当前任务
void dispatchOnCancelled(LoadTask task, D data) {
onCanceled(data);
if (mCancellingTask == task) {
rollbackContentChanged();
mLastLoadCompleteTime = SystemClock.uptimeMillis();
mCancellingTask = null;
if (DEBUG) Log.v(TAG, "Delivering cancellation");
deliverCancellation();
executePendingTask();
}
}
// 如果加载完成
void dispatchOnLoadComplete(LoadTask task, D data) {
// 如果任务已完成,而当前任务对象已改变,执行取消当前任务
if (mTask != task) {
dispatchOnCancelled(task, data);
} else {
// 如果loader被抛弃,通常是用户已经退出Activity
if (isAbandoned()) {
onCanceled(data);
} else {
// 正常完成异步加载,将数据发送到主线程
commitContentChanged();
mLastLoadCompleteTime = SystemClock.uptimeMillis();
mTask = null;
deliverResult(data);
}
}
}
CursorLoader源码
CursorLoader主要是面向ContentProvider的异步查询,它继承自AsyncTaskLoader,包含的成员变量主要有:
// 数据源观察者,如果数据源发生改变会回调
final ForceLoadContentObserver mObserver;
// ContentProvider相关的查询信息
Uri mUri;
String[] mProjection;
String mSelection;
String[] mSelectionArgs;
String mSortOrder;
// 请求返回的结果
Cursor mCursor;
// 取消ContentProvider后台请求的回调
CancellationSignal mCancellationSignal;
真正的后台请求实现方式
@Override
public Cursor loadInBackground() {
synchronized (this) {
if (isLoadInBackgroundCanceled()) {
throw new OperationCanceledException();
}
mCancellationSignal = new CancellationSignal();
}
try {
// 通过ContentResolver查询后台数据
Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
mSelectionArgs, mSortOrder, mCancellationSignal);
if (cursor != null) {
try {
cursor.getCount();
// 注册Cursor的后台数据源观察者,如果数据源变化会发送通告
cursor.registerContentObserver(mObserver);
} catch (RuntimeException ex) {
cursor.close();
throw ex;
}
}
return cursor;
} finally {
synchronized (this) {
mCancellationSignal = null;
}
}
}
@Override
public void cancelLoadInBackground() {
super.cancelLoadInBackground();
// 如果当前异步任务被取消,取消查询
synchronized (this) {
if (mCancellationSignal != null) {
mCancellationSignal.cancel();
}
}
}
// 将查询到的cursor保存到缓存中,如果状态正常就发送给回调
@Override
public void deliverResult(Cursor cursor) {
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
其他覆盖了Loader请求的方法:
// 开始异步加载,如果有缓存对象直接发送回调,
如果没有缓存或者发现数据源发生了改变,强制请求
@Override
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
// 停止加载,直接取消加载
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
// 取消加载如果缓存数据不为空,需要关闭cursor
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
// 重置当前Loader,清空加载的Cursor,取消当前异步请求对象
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
这些方法都已经熟悉了,那么它们到底是怎么集成到Activity/Fragment中的呢,开始请求和取消请求都是在哪里调用的呢,这就需要查看LoaderManager里的代码实现。