在Android中有两种十分常见的异步处理消息的机制,一种是Handler机制一种是asynctask机制,Handler机制有其缺点:
(1)代码臃肿
(2)每一个任务都需要开启一个线程
(3)在多任务同时执行的时候不容易对任务进行控制。
其实asynctask是对Handler的封装,这一点我们可以再asynctask的源码中讲到,首先看一下如何简单的使用asynctask。代码如下
public class MyAsyncTask extends AsyncTask<String ,String,String> {
//在调用execute之后立马被调用
private static final String TAG = "MyAsyncTask";
@Override
protected void onPreExecute() {
Log.e(TAG, "onPreExecute: " +Thread.currentThread());
super.onPreExecute();
}
//后台执行的逻辑代码,不能更新UI
@Override
protected String doInBackground(String... params) {
//执行publishProgress后立马调用onProgressUpdate
Log.e(TAG, "doInBackground: " +Thread.currentThread());
publishProgress("d");
return null;
}
//更新UI
@Override
protected void onProgressUpdate(String... values) {
Log.e(TAG, "onProgressUpdate: " +Thread.currentThread());
super.onProgressUpdate(values);
}
//返回的结果显示在UI控件上
@Override
protected void onPostExecute(String s) {
Log.e(TAG, "onPostExecute: " +Thread.currentThread());
super.onPostExecute(s);
}
//在任务中途取消任务,更新UI。
@Override
protected void onCancelled() {
super.onCancelled();
}
然后就是在MainActivity中我们要实例化一个AsyncTask,代码如下所示。
MyAsyncTask myAsyncTask =new MyAsyncTask();
myAsyncTask.execute("a");
最后执行结果
可以看到AsyncTask依次执行了onPreExecute()、doInBackground()、onProgressUpData()、onPostExecute()。其中只有doInBackground()是在AsyncTask线程中执行的其他均在UI线程中执行。那么他们之间是如何相互调用的呢?
首先我们从mainactivity中的execute进入AsyncTask看一看。在AsyncTask中首先调用了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;
}
在该方法中首先判断了当前AsyncTask的状态,AsyncTask有三种状态,这三种状态在AsyncTask的内部内Status中有体现三种状态分别为PENDING
,RUNNING,FINISHED,当AsyncTask的状态为RUNNING,和FINISHED的时候抛出异常,由此可知Asynctask每一次实例化只能被执行一次,如果多次执行会抛出异常。当Asynctask的状态是PENDING的时候,会首先将状态更改为RUNNING,接着重点来了我们上面说到执行execute的时候会立马执行onPreExecute(),但是我们发现没有接着执行doInBackground()方法啊,不要急我们接着看mWorker,最后发现mWorker,是一个WorkerRunnable类型的,他重写了call()方法。
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;
}
在call()中我们看到了doInBackground()在这里被调用了。当我们在doInBackground()中调用publishProgress("d")的时候
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
可以看到Handler发送了一个消息,这也解释了为什么说Asynctask是对Handler的封装,这个Handler是InternalHandler中定义的
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;
}
}
在这个时候我们发送的是MESSAGE_POST_PROGRESS:消息,在这里Asynctask执行了onProgressUpDate(),当任务执行完毕的时候发送MESSAGE_POST_RESULT这时候执行finish()将数据发送给onPostExecute(),任务结束。
当然虽说Asynctask对Handler进行了很好的封装但是其任然有很多缺点例如:
(1)很多人以为Asynctask会在Activity销毁的时候同时销毁,实际上Asynctask在activity销毁的时候有可能不会被销毁,会一直执行到DoInBackground()执行完毕才会被销毁,同时如果Activity被销毁也有可能造成Asynctask的崩溃,有可能Asynctask操作的View已经被回收造成Asynctask异常。
(2)Asynctask在activity的非静态内部类中定义的时候会持有当前activity的引用,即使我们销毁了当前Activity但是Asynctask仍然会在后台运行,此时当前Activity无法被回收造成内存泄漏。
(3)Asynctask还有可能会丢失运行的结果,例如屏幕旋转或者后台的activity重新被创建,那么Asynctask持有的是之前的Activity的引用,这时调用onPostExecute更新界面将没有作用。
以上就是我对Asynctask的理解了如有理解错误之处还望批评指正。