当前位置: 首页 > web >正文

AsyncTask的使用和工作原理

简介

AsyncTask是一个轻量级的异步任务类,封装了Handler和Thread,可以方便的在线程池里执行后台任务,并把进度和结果发送到主线程并在主线程中更新UI。AsyncTask应该用来执行比较短的后台任务,一般是以秒为单位的。如果需要保持线程长期运行,建议用线程池进行。

一个AsyncTask是一个抽象的泛型类,通过继承的方式来使用。AsyncTask需要指定三个三个泛型参数的类型,重写四个回调方法。

三个泛型

三个泛型参数分别是Params, Progress and Result

  • Params:初始化AsyncTask时传入的参数类型,用来定义传递给后台任务的参数类型。
  • Progress:后台任务执行进度的类型。
  • Result:后台任务执行完成返回的结果类型。

当不需要相应的参数的时候,也可定义成Void类型。

四个方法
  • onPreExecute(),后台任务执行前在UI线程中调用,一般用来做一些初始化工作,比如显示progress bar等。
  • doInBackground(Params…),在onPreExecute()方法执行之后,在后台线程中调用,用来处理耗时的后台任务,执行完成之后将结果return。在这个方法中可以调用publishProgress(Progress…)将执行进度发送到主线程的回调方法onProgressUpdate(Progress…)。
  • onProgressUpdate(Progress…),在调用publishProgress(Progress…)方法之后会在主线程中回调这个方法。主要用来更新后台任务的执行进度。
  • onPostExecute(Result),在后台任务执行完成之后在UI线程中调用。后台任务执行结果会作为一个参数传递到这个方法中,一般用来更新UI。
取消任务

AsyncTask可以调用cancel(boolean)方法取消执行,该方法调用之后,调用isCancelled()方法会返回true,后台任务执行完成后,不再调用onPostExecute(Object),而是调用onCancelled(Object)。为了尽快的取消任务,应该在doInBackground(Object[])方法中尽可能的调用isCancelled()判断任务是否被取消。

使用方法

AsyncTask必须通过继承的方式使用。子类至少复写onInBackground(Params…)方法,一般还会复写onPostExecute(Result)方法。如下使用一个模拟下载文件的例子:

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 calledif (isCancelled()) break;}return totalSize;}protected void onProgressUpdate(Integer... progress) {setProgressPercent(progress[0]);}protected void onPostExecute(Long result) {showDialog("Downloaded " + result + " bytes");}}

写好子类之后,执行就比较简单。

new DownloadFilesTask().execute(url1, url2, url3);
注意事项

AsyncTask使用有一些限制,需要注意:

  • AsyncTask类必须在UI线程中加载。在Android4.1之后由系统自动完成。
  • AsyncTask实例必须在UI线程中创建。
  • execute(Params…)方法必须在UI线程中调用。
  • 不要手动调用提供的四个回调方法。
  • 每个AsyncTask实例只能执行一次。
版本演化

AsyncTask类经过几次的版本演化,一开始的AsyncTask是顺序执行的,从Android1.6开始,改成了线程池,允许多个AsyncTask并行执行。直到Android3.0开始,为了避免并发引起的错误,AsyncTask又改成默认为顺序执行,但可以通过executeOnExecutor()方法并发执行。

AsyncTask的工作原理

为了分析AsyncTask的工作原理,从execute(Params… params)方法入手。

public final AsyncTask<Params, Progress, Result> execute(Params... params) {return executeOnExecutor(sDefaultExecutor, params);
}

execute(Params… params)方法又调用了executeOnExecutor(Executor exec, Prams… params)方法。

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;
}

从上面的源码可以看到,在AsyncTask执行的时候,就调用了onPreExecute()方法,然后将params参数封装成FutureTask对象,调用了线程池sDefaultExecutor的execute(mFuture)方法。线程池sDefaultExecutor实际就是一个串行的线程池,我们来看一下sDefaultExecutor线程池的实现。

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();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);}}}

从这里可以看到,在SerialExecutor中,FutureTask作为Runnable对象传进来之后,会把FutureTask插入任务队列mTasks中,如果当前没有正在活动的AsyncTask,就会调用sheduleNext()方法,如果有正在活动的AsyncTask,则在执行结束之后调用sheduleNext()方法,直到所有的任务执行完成。可以看得出来SerialExecutor是串行执行的。而真正执行的线程池为THREAD_POOL_EXECUTOR,SerialExecutor是对THREAD_POOL_EXECUTOR的封装。

在THREAD_POOL_EXECUTOR的execute()方法中最后调用了run方法。

public void run() {...try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {result = c.call();ran = true;...
}

而在FutureTask执行run方法时,会执行Callable的call()方法,从AsyncTask的构造方法中可以发现,对应的是mWorker的call()方法。

mWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {mTaskInvoked.set(true);Result result = null;try {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedresult = doInBackground(mParams);Binder.flushPendingCommands();} catch (Throwable tr) {mCancelled.set(true);throw tr;} finally {postResult(result);}return result;}
};mFuture = new FutureTask<Result>(mWorker) {
...

在call()方法中,执行了doInBackground(mParams)方法,然后将返回值传递给postResult(result)中。

private Result postResult(Result result) {@SuppressWarnings("unchecked")Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();return result;
}

而在postResult(Result)方法中,将result包装成Message,发送给Handler,跟踪getHandler()找到对应的Handler为InternalHandler。

private static class InternalHandler extends Handler {public InternalHandler(Looper looper) {super(looper);}@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {case MESSAGE_POST_RESULT:// There is only one resultresult.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS:result.mTask.onProgressUpdate(result.mData);break;}}
}

InternalHandler收到MESSAGE_POST_RESULT消息之后,调用AsyncTask的finish()方法。

private void finish(Result result) {if (isCancelled()) {onCancelled(result);} else {onPostExecute(result);}mStatus = Status.FINISHED;
}

如果AsyncTask取消执行了,就调用onCancelled()方法,否则调用onPostExecute()方法。

http://www.xdnf.cn/news/11448.html

相关文章:

  • estore简版商城思路
  • 深入理解java.lang.InstantiationError异常
  • JNI常用数据类型转换库函数使用总结
  • 分享我免费可用API接口网站
  • bootstrap方法_【统计学】bootstrap方法
  • 软件测试方法_边界值分析法
  • 地图上分成一块一块区域 高德地图_开车用哪个导航最好?看看老司机总结的地图对比,学会不吃亏...
  • Couchbase数据备份与恢复
  • CountDownTimer 倒计时,定时器工具类
  • WTL简介
  • C#对ListBox控件中的数据进行的操作
  • JVM内存配置详
  • 高级分布式系统-第11讲 现场总线技术
  • 杭电oj--人见人爱A+B 2033
  • 线性回归(Linear Regression)
  • 一个外国的好网站 http://www.ilovejackdaniels.com/
  • Serialization即序列化全解析(转)
  • 无线网络领域国际会议/期刊排名
  • CSS教程:div垂直居中的N种方法
  • SLIC超像素分割详解(一)(二)(三)
  • verilog之testbench的写法
  • 免费标准下载网站
  • 为什么需要协调能力?如何提高协调能力?
  • ENet特性简介
  • SQL Server 数据库
  • 轻松搞定!png格式图片怎么弄?详细方法一网打尽
  • 电脑提示由于找不到xinput1_3.dll,无法继续执行代码有什么好的解决办法
  • Python批量下载ts视频文件,并用ffmpeg合并
  • AI人工智能原理与Python实战:Python人工智能行业应用 2
  • 低级格式化软件测试,低级格式化,几款优秀的低级格式化工具对比制作步骤