AsyncTaskLoader
AsyncTaskLoader的源码不是很多 300多行,AsyncTaskLoader是Loader的一个实现类,官方给出了案例:
https://developer.android.com/reference/android/content/AsyncTaskLoader.html
AsyncTaskLoader内部类LoadTask继承ModernAsyncTask类,并实现Runnable接口。加载数据就是通过LoadTask的doInBackground方法调用AsyncTaskLoader的onLoadInBackground方法获取到的数据。ModernAsyncTask其异步根本就是使用线程池+Handler实现的。
Loader异步加载器,异步加载就体现在这个类中。ModernAsyncTask使用LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素。
使用AtomicBoolean,在这个Boolean值的变化的时候不允许在之间插入,保持操作的原子性。
构造中创建要执行的任务。WorkerRunnable就是一个runnable,在executeOnExecutor方法被AsyncTaskLoader中的方法调用时,首先会执行WorkerRunnable去获取数据,等数据获取到,就会把结果分发下去,分发到Loader的回调用法中。
public ModernAsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
@Override
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
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 {
final Result result = get();
postResultIfNotInvoked(result);
} 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);
} catch (Throwable t) {
throw new RuntimeException(
"An error occurred while executing doInBackground()", t);
}
}
};
}
执行这个方法,启动线程工作。这个方法是在哪里调用的呢?是在AsyncTaskLoader的executePendingTask方法。调用这个方法,才能执行在ModernAsyncTask构造中创建的task任务。
public final ModernAsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
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;
}
public abstract class AsyncTaskLoader<D> extends Loader<D> {
static final String TAG = "AsyncTaskLoader";
static final boolean DEBUG = false;
final class LoadTask extends ModernAsyncTask<Void, Void, D> implements Runnable {
//CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
private final CountDownLatch mDone = new CountDownLatch(1);
// Set to true to indicate that the task has been posted to a handler for
// execution at a later time. Used to throttle updates.
boolean waiting;
//运行在子线程,用与加载数据。
/* Runs on a worker thread */
@Override
protected D doInBackground(Void... params) {
if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
try {
//调用AsyncTaskLoader的onLoadInBackground会调用你自己实现的loadInBackground方法来获取数据。
D data = AsyncTaskLoader.this.onLoadInBackground();
if (DEBUG) Log.v(TAG, this + " <<< doInBackground");
return data;
} catch (OperationCanceledException ex) {
if (!isCancelled()) {
// onLoadInBackground threw a canceled exception spuriously.
// This is problematic because it means that the LoaderManager did not
// cancel the Loader itself and still expects to receive a result.
// Additionally, the Loader's own state will not have been updated to
// reflect the fact that the task was being canceled.
// So we treat this case as an unhandled exception.
throw ex;
}
if (DEBUG) Log.v(TAG, this + " <<< doInBackground (was canceled)", ex);
return null;
}
}
/* Runs on the UI thread */
//运行在UI线程。当doInBackground方法执行完毕,就会调用这个方法分发结果。
@Override
protected void onPostExecute(D data) {
if (DEBUG) Log.v(TAG, this + " onPostExecute");
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
// N个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的;每调用一次这个方法,在构造函数中初始化的count值就减1。所以当N个线程都调 用了这个方法,count的值等于0,然后主线程就能通过await()方法,恢复执行自己的任务
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();
}
}
/* Runs on the UI thread, when the waiting task is posted to a handler.
* This method is only executed when task execution was deferred (waiting was true). */
@Override
public void run() {
waiting = false;
AsyncTaskLoader.this.executePendingTask();
}
/* Used for testing purposes to wait for the task to complete. */
public void waitForLoader() {
try {
mDone.await();
} catch (InterruptedException e) {
// Ignore
}
}
}
private final Executor mExecutor;
volatile LoadTask mTask;
volatile LoadTask mCancellingTask;
long mUpdateThrottle;
long mLastLoadCompleteTime = -10000;
Handler mHandler;
public AsyncTaskLoader(Context context) {
this(context, ModernAsyncTask.THREAD_POOL_EXECUTOR);
}
private AsyncTaskLoader(Context context, Executor executor) {
super(context);
mExecutor = executor;
}
/**
* Set amount to throttle updates by. This is the minimum time from
* when the last {@link #loadInBackground()} call has completed until
* a new load is scheduled.
*
* @param delayMS Amount of delay, in milliseconds.
*/
public void setUpdateThrottle(long delayMS) {
mUpdateThrottle = delayMS;
if (delayMS != 0) {
mHandler = new Handler();
}
}
@Override
protected void onForceLoad() {
super.onForceLoad();
cancelLoad();
mTask = new LoadTask();
if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
executePendingTask();
}
@Override
protected boolean onCancelLoad() {
if (DEBUG) Log.v(TAG, "onCancelLoad: mTask=" + mTask);
if (mTask != null) {
if (!mStarted) {
mContentChanged = true;
}
if (mCancellingTask != null) {
// There was a pending task already waiting for a previous
// one being canceled; just drop it.
if (DEBUG) Log.v(TAG,
"cancelLoad: still waiting for cancelled task; dropping next");
if (mTask.waiting) {
mTask.waiting = false;
mHandler.removeCallbacks(mTask);
}
mTask = null;
return false;
} else if (mTask.waiting) {
// There is a task, but it is waiting for the time it should
// execute. We can just toss it.
if (DEBUG) Log.v(TAG, "cancelLoad: task is waiting, dropping it");
mTask.waiting = false;
mHandler.removeCallbacks(mTask);
mTask = null;
return false;
} else {
boolean cancelled = mTask.cancel(false);
if (DEBUG) Log.v(TAG, "cancelLoad: cancelled=" + cancelled);
if (cancelled) {
mCancellingTask = mTask;
cancelLoadInBackground();
}
mTask = null;
return cancelled;
}
}
return false;
}
/**
* Called if the task was canceled before it was completed. Gives the class a chance
* to clean up post-cancellation and to properly dispose of the result.
*
* @param data The value that was returned by {@link #loadInBackground}, or null
* if the task threw {@link OperationCanceledException}.
*/
public void onCanceled(D data) {
}
//执行任务,
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)) {
// Not yet time to do another load.
if (DEBUG) Log.v(TAG, "Waiting until "
+ (mLastLoadCompleteTime+mUpdateThrottle)
+ " to execute: " + mTask);
mTask.waiting = true;
mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);
return;
}
}
if (DEBUG) Log.v(TAG, "Executing: " + mTask);
mTask.executeOnExecutor(mExecutor, (Void[]) null);
}
}
//onCanceled是你自己的实现,在这里应该释放数据的资源。
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");
//分发Loader取消事件,最后调用的是LoaderManager#onLoadCanceled方法。彻底销毁Loader。
deliverCancellation();
//执行等待的task任务。
executePendingTask();
}
}
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);
}
}
}
/**
* Called on a worker thread to perform the actual load and to return
* the result of the load operation.
*
* Implementations should not deliver the result directly, but should return them
* from this method, which will eventually end up calling {@link #deliverResult} on
* the UI thread. If implementations need to process the results on the UI thread
* they may override {@link #deliverResult} and do so there.
*
* To support cancellation, this method should periodically check the value of
* {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
* Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
* directly instead of polling {@link #isLoadInBackgroundCanceled}.
*
* When the load is canceled, this method may either return normally or throw
* {@link OperationCanceledException}. In either case, the {@link Loader} will
* call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
* result object, if any.
*
* @return The result of the load operation.
*
* @throws OperationCanceledException if the load is canceled during execution.
*
* @see #isLoadInBackgroundCanceled
* @see #cancelLoadInBackground
* @see #onCanceled
*/
public abstract D loadInBackground();
/**
* Calls {@link #loadInBackground()}.
*
* This method is reserved for use by the loader framework.
* Subclasses should override {@link #loadInBackground} instead of this method.
*
* @return The result of the load operation.
*
* @throws OperationCanceledException if the load is canceled during execution.
*
* @see #loadInBackground
*/
protected D onLoadInBackground() {
return loadInBackground();
}
/**
* Called on the main thread to abort a load in progress.
*
* Override this method to abort the current invocation of {@link #loadInBackground}
* that is running in the background on a worker thread.
*
* This method should do nothing if {@link #loadInBackground} has not started
* running or if it has already finished.
*
* @see #loadInBackground
*/
public void cancelLoadInBackground() {
}
/**
* Returns true if the current invocation of {@link #loadInBackground} is being canceled.
*
* @return True if the current invocation of {@link #loadInBackground} is being canceled.
*
* @see #loadInBackground
*/
public boolean isLoadInBackgroundCanceled() {
return mCancellingTask != null;
}
/**
* Locks the current thread until the loader completes the current load
* operation. Returns immediately if there is no load operation running.
* Should not be called from the UI thread: calling it from the UI
* thread would cause a deadlock.
* <p>
* Use for testing only. <b>Never</b> call this from a UI thread.
*
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
public void waitForLoader() {
LoadTask task = mTask;
if (task != null) {
task.waitForLoader();
}
}
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
if (mTask != null) {
writer.print(prefix); writer.print("mTask="); writer.print(mTask);
writer.print(" waiting="); writer.println(mTask.waiting);
}
if (mCancellingTask != null) {
writer.print(prefix); writer.print("mCancellingTask="); writer.print(mCancellingTask);
writer.print(" waiting="); writer.println(mCancellingTask.waiting);
}
if (mUpdateThrottle != 0) {
writer.print(prefix); writer.print("mUpdateThrottle=");
TimeUtils.formatDuration(mUpdateThrottle, writer);
writer.print(" mLastLoadCompleteTime=");
TimeUtils.formatDuration(mLastLoadCompleteTime,
SystemClock.uptimeMillis(), writer);
writer.println();
}
}
}