频道
bg

关于AsyncTaskLoader

coding七月 01, 20151mins
Android Concurrency

Concurrency基础H1

ExecutorH2

Executor是一个用来执行Runable实例的对象,接口定义如下

bash

/**
* An object that executes submitted {@link Runnable} tasks. This
* interface provides a way of decoupling task submission from the
* mechanics of how each task will be run, including details of thread
* use, scheduling, etc. An {@code Executor} is normally used
* instead of explicitly creating threads.
*/
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}

ExecutorServiceH2

ExecutorService继承自Executor,也是用来执行Runable对象的,但是额外提供了方法能够返回Future对象用来跟踪异步任务的状态

ThreadPoolExecutor、ScheduledThreadPoolExecutorH2

都是ExecutorService的实现类,ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,提供了重复执行异步任务的功能

ExecutorsH2

ExecutorServiceCallable等的工厂类工具了,提供了一些方法返回各种ExecutorService的实例类,以及可以把Runnable转换成Callable实例

RunnableH2

Runnable代表可执行线程的单元。

bash

public class SimpleTask implements Runnable{
@Override
public void run() {
System.out.println("SimpleTask, Runnable: Executing Logic");
}
}
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
// Step1 : Create a Runnable
Runnable simpleTask = new SimpleTask();
// Step 2: Configure Executor
// Uses FixedThreadPool executor
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(simpleTask);
executor.shutdown();
}
}

CallableH2

Runnable类似,但是它可以返回值、抛出异常

bash

public class CallableTask implements Callable<String>{
@Override
public String call() throws Exception {
String s="Callable Task Run at "+System.currentTimeMillis();
return s;
}
}
public class CallableClient {
/**
* @param args
*/
public static void main(String[] args) {
// Step1 : Create a Runnable
Callable callableTask = new CallableTask();
// Step 2: Configure Executor
// Uses FixedThreadPool executor
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future = executor.submit(callableTask);
boolean listen = true;
while (listen) {
if (future.isDone()) {
String result;
try {
result = future.get();
listen = false;
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

FutureH2

代表一个异步执行的结果。可以用来查询最终的执行结果以及查询异步任务的状态

FutureTaskH2

实现一个可以取消的异步执行。它实现了RunnableFuture接口,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

Android LoaderH1

AsyncTaskH2

AsyncTask提供一个更为简单的方式使用UI线程的机制,它允许我们在其他线程执行后台操作,最终把执行结果push回UI线程。 需要在后台执行的逻辑需要实现在doInBackground方法,最终执行这个AsyncTask需要调用execute方法。

AsyncTask会在初始化的时候实例化一个实现了Runnable接口的WorkerRunnable,在它的call方法的逻辑中主要调用了需要子类实现的doInBackground方法:

bash

mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};

同时还会初始化一个FutureTask对象实例:

bash

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 occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};

最终调用execute方法的时候就会执行上述的FutureTask实例

ModernAsyncTaskH2

ModernAsyncTaskAsyncTask的一个拷贝,它仅仅包括了用来支持AsyncTaskLoader的代码,因为它需要其中一部分的功能。

AsyncTaskLoaderH2

AsyncTaskLoader继承子Loader,主要用来通过异步任务来加载数据。所以它内部有一个继承自ModernAsyncTask的内部类LoadTask的成员变量,AsyncTaskLoader最终的异步执行都是代理给这个成员变量来执行的。

bash

final class LoadTask extends ModernAsyncTask<Void, Void, D> implements Runnable {
D result;
boolean waiting;
private CountDownLatch done = new CountDownLatch(1);
/* Runs on a worker thread */
@Override
protected D doInBackground(Void... params) {
if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
result = AsyncTaskLoader.this.onLoadInBackground();
if (DEBUG) Log.v(TAG, this + " <<< doInBackground");
return result;
}
/* 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 {
done.countDown();
}
}
@Override
protected void onCancelled() {
if (DEBUG) Log.v(TAG, this + " onCancelled");
try {
AsyncTaskLoader.this.dispatchOnCancelled(this, result);
} finally {
done.countDown();
}
}
@Override
public void run() {
waiting = false;
AsyncTaskLoader.this.executePendingTask();
}
}

可以看到LoadTask还实现了Runnable接口,并且在实现逻辑中调用了AsyncTaskLoaderexecutePendingTask方法。 executePendingTask最终则会执行这个LoadTask的异步代码:

bash

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(ModernAsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
}

除了Runnable接口之外,forceLoad方法也调用了executePendingTask会执行实际的异步任务。而且实际我也发现这个Runnable对象也没有在另外的线程中执行。

所以我们的实现了LoaderCallbacks#onCreateLoader的方法后会发现,Loader并没有执行,而是要调用forceLoad方法才会执行。当然更合理的是把调用移到onStartLoading中:

bash

@Override
protected void onStartLoading() {
if (data != null)
deliverResult(data);
if (takeContentChanged() || data == null)
forceLoad();
}

其他的一些问题H1

forceLoad的问题H2

每次Loader开始执行后,在执行完成deliverResult之前,如果再次执行forceLoad,那么上一次直接结果最终并不会执行onLoadFinished方法。原因如下:

上面的分析看到LoadTask的onPostExecute会调用AsyncTaskLoader的dispatchOnLoadComplete方法:

bash

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 {
mLastLoadCompleteTime = SystemClock.uptimeMillis();
mTask = null;
if (DEBUG) Log.v(TAG, "Delivering result");
deliverResult(data);
}
}
}

AsyncTaskLoader的onForceLoader方法又是会重新创建LoadTask的实例

bash

@Override
protected void onForceLoad() {
super.onForceLoad();
cancelLoad();
mTask = new LoadTask();
if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
executePendingTask();
}

所以最终的执行结果并不会传递到LoaderManager中。

评论


新的评论

匹配您的Gravatar头像

Joen Yu

@2022 JoenYu, all rights reserved. Made with love.