Android多线程编程之AsyncTask学习篇(二)
来源:互联网 发布:赤壁赋一词多义知乎 编辑:程序博客网 时间:2024/06/05 10:49
Android多线程编程之AsyncTask学习篇(二)
一、AsyncTask之初识
AysncTask比较适用于UI线程,这个类可以在不需要操纵线程或者是Handler的情况下执行后台操作和发布结果到UI主线程中。AsyncTask通过线程池和Handler以及不构成通用线程框架来设计成一个帮助类。AsyncTask比较适用于执行轻量级的后台耗时任务操作(至多是几秒钟的),如果需要用线程执行比较长的耗时任务操作,那么建议适用线程池。
(一)AysncTask是一种轻量级的异步任务类,用来执行后台任务,然后把执行的进度和最终的结果传递给主线程(UI线程)中更新UI。
(二)AysncTask是一个抽象的泛型类,它提供了Params,Progress,Result这三个泛型参数。
(三)AysncTask提供了四个核心的方法
- onPreExecute 在主线程中执行,在异步任务执行之前,此方法会被调用,一般可以做一些准备工作,例如在用户交互界面显示一个进度条。
- doInBackground 等onPreExecute()方法执行完后在线程池(后台线程)中执行,这一步主要是用于执行后台耗时任务操作,异步任务的参数传递到这一步。计算的结果在这一步返回,将传回的结果传递到后一步,这一步也用于更新一个或者多个单元的进度, 这些值通过onProgressUpdate方法在主线程也即UI线程中更新。
- onProgressUpdate 在UI主线程被调用,执行的时机没有定义,这个方法主要是用于当后台任务任然在执行中在UI界面显示相应的进度信息。例如,它可以用一个滚动的进度条或者显示文本信息来表示。
- onPostExecute 该线程主要是在后台任务执行完后,此方法会在UI主线程中被调用,其中那个后台任务返回的结果会传递到这个方法中。
以上可以用一个简单的实例来说明,代码如下:
public class AsyncTaskTest extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); Log.v("AsyncTaskTest", Thread.currentThread().getName() + "---->onPreExecute"); } @Override protected Object doInBackground(Object[] params) { Log.v("AsyncTaskTest", Thread.currentThread().getName() + "---->doInBackground"); publishProgress(10);//在工作线程中执行,非UI线程执行。 return null; } @Override protected void onProgressUpdate(Object[] values) { super.onProgressUpdate(values); Log.v("AsyncTaskTest", Thread.currentThread().getName() + "---->onProgressUpdate"); } @Override protected void onPostExecute(Object o) { super.onPostExecute(o); Log.v("AsyncTaskTest", Thread.currentThread().getName() + "---->onPostExecute"); }}
在主线程中执行new AsyncTaskTest().execute(“AsyncTaskTest”);
打印的日志为:
从运行结果可以看出四个方法的运行顺序,以及每个方法在什么线程中执行的,也证实了上面四点中的原则。
在使用AysncTask过程中,需要注意以下几个规则:
- AsyncTask的类必须在UI主线程中加载,意味着第一次访问必须发生在主线程中。
- AsyncTask的对象必须在主线程中创建。
- excute方法必须在UI主线中调用。
- 不要在程序中直接使用onPreExecute,onPostExecute,doInBackground,onProgressUpdate方法。
- 一个AsyncTask对象只能执行一次,即只能调用一次excute方法,否则会报运行异常。
二、工作原理
在Android 3.0版本之前采用的是并行的执行任务,这在ActivityThread(UI主线程)中的handleBindApplication方法中可以得到验证。
private void handleBindApplication(AppBindData data) { ... // If the app is Honeycomb MR1 or earlier, switch its AsyncTask // implementation to use the pool executor. Normally, we use the // serialized executor as the default. This has to happen in the // main thread so the main looper is set right.
if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) { AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }
...}
当Android系统版本小于等于3.0时,AsyncTask会执行setDefaultExecutor方法,将采用并行的方式来执行任务,高于3.0版本时,则会采用默认的串行的方式来执行任务。
下面主要分析串行的方式来执行一步任务,先看下AsyncTask的构造函数:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/ public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); } }; 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); } } };}
从源代码的注释就可以知道AsyncTask创建的是一个异步任务,只能在UI主线程中创建并且调用。
下面再来看下AsyncTask的执行方法execute(),execute实际调用了executeOnExecutor方法,其中sDefaultExecutor 是一个串行的线程池,一个进程中的所有AsyncTask全部在这个串行的线程池中排队执行。
@MainThreadpublic 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;}
调用execute方法时,首先判断执行状态,如果没有处于执行状态,那么标志为执行中(mStatus = Status.RUNNING)。并且先调用onPreExecute()方法,之后将传入的参数赋值给mWorker,mFeature相当于Runable对象,mFeature会插入到任务队列中,如果没有活动的任务,就会调用SerialExecutor
中的scheduleNext方法来执行下一个任务,以此类推。而其中真正执行任务的线程池是THREAD_POOL_EXECUTOR,SerialExecutor线程池主要是对任务进行排列。mFeature中的run方法执行后会调用mWorker中的call方法,call方法在线程池中执行。从AsyncTask构造函数中可知,紧接着会执行doInbackground方法,并将返回结果传递给postResult方法。
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result;}
private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @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; } }}
在postResult方法中会使用Handler发送消息给主线程中,如果没有在doInBackground方法中执行publishProgress方法,那么会result.mTask.finish(result.mData[0]);
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED;}
如果取消了AsyncTask,那么会执行onCancelled方法。如果没有取消,则会执行onPostExecute方法。
如果在doInBackground方法中执行publishProgress方法,那么会先执行Handler中的result.mTask.onProgressUpdate(result.mData);之后再执行finish方法。
为了在主线程中能刷新UI,那么AsyncTask必须在满足
- AsyncTask的类必须在UI主线程中加载,意味着第一次访问必须发生在主线程中。
- AsyncTask的对象必须在主线程中创建。
- excute方法必须在UI主线中调用。
这几条规则,那么Handler才会起作用。
另外要注意一点的是,如果Android系统版本是3.0以下,AsyncTask是并行执行的。在3.0以上是串行执行的,如果想在3.0版本以上也是并行执行,可以使用AysncTask的executeOnExecutor调用任务。
备注:这里大家还需要进一步了解一下FeatureTask是如何工作的,以及Callable的工作原理,才能更加清晰AsyncTask的工作机制,在这里就不再详细讲解了。
想要了解FeatureTask的工作机制,可以查阅《Java并发编程的艺术》一书中的第十章的第四小节内容。需要pdf版电子书的可以给我留言。
- Android多线程编程之AsyncTask学习篇(二)
- android多线程之AsyncTask的初步认识(二)
- Android多线程编程之三:AsyncTask
- android多线程编程之AsyncTask与Handler
- Android多线程编程AsyncTask
- Android多线程编程、异步机制(AsyncTask)
- android多线程之AsyncTask
- Android--多线程之AsyncTask
- android多线程之AsyncTask
- android多线程之AsyncTask
- Android多线程之AsyncTask
- Android多线程之AsyncTask
- Android多线程之AsyncTask
- Android 多线程-----AsyncTask详解(学习)
- Android之AsyncTask(二)
- Android编程AsyncTask学习
- android多线程学习---AsyncTask分析
- Android之AsyncTask异步加载(二)
- Openstack MOS 8.0安装教程
- 1202 子序列个数
- vi命令
- 对象的原型链
- 关于Java中的final
- Android多线程编程之AsyncTask学习篇(二)
- RxJava操作符(03-变换操作)
- Binder学习笔记(十一)—— 智能指针
- 【Unity填坑日记】UGUI崩溃巨坑:UI::CanvasRenderer::SyncDirtyElements
- Swap Nodes in Pairs
- Centos 7 静态IP设置
- vmware 不能更改网络为桥接:已没有未桥接的主机网络适配器
- 《Learn More Study Less》笔记总结
- 代码备份jquery.smart.js