AsyncTask的使用大家应该都不陌生,内部原理就是线程池
与Handler
的运用。
简单的使用
// 泛型参数 第一个参数 Params 第二个参数 Progress 第三个参数 Result
// Params:开始异步任务执行时传入的参数类型;
// Progress:异步任务执行过程中,返回下载进度值的类型; publishProgress发送
// Result:异步任务执行完成后,返回的结果类型; onPostExecute(Boolean result)
public class DownLoadAsyncTask extends AsyncTask<Void, Integer, Boolean> {
ProgressDialog progressDialog = ProgressDialog.getInstance();
private int percent = 0;
private Context context;
public DownLoadAsyncTask(Context context) {
this.context = context;
}
@Override
protected void onPreExecute() {
// UI 线程 开启前初始化
ProgressDialog.getInstance().show(this.context);
new Thread(new Test());
}
@Override
protected Boolean doInBackground(Void... params) {
// 在独立线程执行
try {
while (true) {
int downloadPercent = doDownload();
publishProgress(downloadPercent);
if (downloadPercent >= 1000) {
break;
}
}
} catch (Exception e) {
return false;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
// UI 线程
//progressDialog.show("当前下载进度:" + values[0] + "%");
}
@Override
protected void onPostExecute(Boolean result) {
// 主线程中运行
progressDialog.dismiss();
if (result) {
Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
}
}
public int doDownload() {
percent++;
return percent;
}
class Test implements Runnable{
@Override
public void run() {
}
}
}
现在有个疑问是 怎么做到线程切换的?
look look源码 - -
// 先看看构造函数
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
// WorkerRunnable 实现了Callable接口 这边只是实例化 没有开启 call执行了耗时操作doInBackground方法
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
// FutureTask 实现了runnble接口 接收mWorker
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);
}
}
};
}
// 再看execute 方法
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
......
// 主线程execute调用的的 onPreExecute当然在主线程中(也可以在非UI线程启动,onPreExecute就运行在非UI线程),之后的版本AsyncTask可以在子线程创建,切换线程直接获取Ui线程的Looper进行创建Handler
onPreExecute();
// 这边执行了耗时任务 调用了SerialExecutor的execute方法
exec.execute(mFuture);
......
}
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
// 向队列中加入一个新的任务,实例化后的mFuture对象。
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
// 执行THREAD_POOL_EXECUTOR.execute(mActive); 开启线程执行
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
看到现在还是找不到怎么切换线程的 - -
往回看 线程执行时发生了什么?
postResultIfNotInvoked(get()); ->postResult(result);
// 重点还是postResult
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
// getHandler() 返回主线程的Handler
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
// 往主线程发送消息
message.sendToTarget();
return result;
}
getHandler()得到的是InternalHandler 在主线程创建执行完成线程切换
// 静态类 在主线程创建执行handleMessage 完成线程切换
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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
// 任务取消 onCancelled mTask是在主线程执行的
onCancelled(result);
} else {
// 任务完成执行onPostExecute
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
// 还有问题是多个AsyncTask怎么执行的 ?串行?并行?
答案是默认串行
为什么?
还是得看execute()默认如何执行?
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
这段代码很简单就是执行executeOnExecutor
,看看executeOnExecutor
怎么执行的
public final AsyncTask<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;
}
接着看SerialExecutor
的execute
方法
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();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
可以在上面这段代码中看出来先执行异步任务,执行完之后再去下一个任务scheduleNext
,这样就肯定是串行执行的。
知道了默认串行执行,那怎么改成并发的呢?
代码里有一段代码
/**
* An {@link Executor} that can be used to execute tasks in parallel.
* 翻译 :可以用来并行执行任务
*/
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;
}
可以使用executeOnExecutor(THREAD_POOL_EXECUTOR)
这样就相当于直接使用线程池并发执行任务。