摘要:在 android 中实现耗时的操作有很多种实现方式,比如线程(线程池、Callable、FutureTask等等),这些实现方式有各自的好处,具体使用也有差别,一般线程执行为是没有结果返回的,利用FuTureTask可以实现返回结果。
在 Android 中用异步任务来实现耗时操作可以说是很方便,开发者不需要过多关注怎么在 UI 线程和子线程之间的操作。
在分析 AsyncTask 之前先看一下官方 Demo 如何使用这个类
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
* protected Long doInBackground(URL... urls) {
* int count = urls.length;
* long totalSize = 0;
* for (int i = 0; i < count; i++) {
* totalSize += Downloader.downloadFile(urls[i]);
* publishProgress((int) ((i / (float) count) * 100));
* // Escape early if cancel() is called
* if (isCancelled()) break;
* }
* return totalSize;
* }
*
* protected void onProgressUpdate(Integer... progress) {
* setProgressPercent(progress[0]);
* }
*
* protected void onPostExecute(Long result) {
* showDialog("Downloaded " + result + " bytes");
* }
* }
这里主要是三个方法:onPreExecute,doInBackground,onPostExecute
这里做个简单说明一下 onPreExecute 用于实现子线程开始之前的准备工作,例如初始化进度的Bar,doInBackground 这个方法用于进行耗时操作,比如从网络下载东西,数据库操作等等,onPostExecute 用于异步操作之后的结果显示。
知道了使用之后这里提出两个疑问:1、怎么在子线程跟 UI 线程之间切换。
2、doInBackground 执行完的结果怎么作为参数给 onPostExecute。
知道了这两个答案之后那么我们对这个类也就了解的七七八八了。
首先来看 AsyncTask 的构造函数
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler(): new Handler(callbackLooper);
mWorker = new WorkerRunnable
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;
}
};
AsyncTask 有多个构造函数,最后都是调用这个函数,这里有两个类需要注意的是 mHandler 、mWorker , 这个 mHandler 很好理解就是就是主线程的 Handler,估计切换到 UI 线程就是靠这个的了。那这个 mWorker 呢? 是用来干什么的呢? 别急这里先看这个类是怎么实现的:
private static abstract class WorkerRunnable
Params[] mParams;
}
很简单就是实现一个 Callable 接口,这里有个 call 方法,该方法是在子线程中执行的,这里有两句比较眼熟的语句:
result = doInBackground(mParams);
postResult(result);
doInBackground 这个没什么好说就是刚方法执行完后返回一个结果, call 方法是在子线程,该方法肯定也是在子线程。
看看 postResult 方法是如何实现的
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult
message.sendToTarget();
return result;
}
getHandler()就是初始化的 mHandler ,该类实现如下
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:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
到这里就回答了一开始的两个问题了。
AsyncTask 还有个很重要的方式就是 execute,
public final AsyncTask
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask
Params... params) {
if (mStatus != Status.PENDING) {//一个 AsyncTask 实例,该方法只可以执行一次
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();//UI线程
mWorker.mParams = params;
exec.execute(mFuture); //线程池来执行
return this;
}
到这里 AsyncTask 基本上是分析完成了,关于里面线程池的话还有更多的细节,可以自定义线程池或者用默认的线程池,线程池又有对线程的数量做了限制。