耗时操作?更新UI?这些都是我们经常听到的词汇了,最常用的方法就是Thread+Handler的方法,今天就来聊聊另一个熟悉的Asynctask,或许你没有听过,别着急,通过本次(API23)的源码进行讲解,你就明白了。
首先,通过一个简单的例子来看下Asynctask的写法:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private ProgressDialog mDialog;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.id_tv);
mDialog = new ProgressDialog(this);
mDialog.setMax(100);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setCancelable(false);
new MyAsyncTask().execute();
}
private class MyAsyncTask extends AsyncTask<Void, Integer, Void>
{
@Override
protected void onPreExecute()
{
mDialog.show();
Log.e(TAG, Thread.currentThread().getName() + " onPreExecute ");
}
@Override
protected Void doInBackground(Void... params)
{
// 模拟数据的加载,耗时的任务
for (int i = 0; i < 100; i++)
{
try
{
Thread.sleep(80);
} catch (InterruptedException e)
{
e.printStackTrace();
}
publishProgress(i);
}
Log.e(TAG, Thread.currentThread().getName() + " doInBackground ");
return null;
}
@Override
protected void onProgressUpdate(Integer... values)
{
mDialog.setProgress(values[0]);
Log.e(TAG, Thread.currentThread().getName() + " onProgressUpdate ");
}
@Override
protected void onPostExecute(Void result)
{
// 进行数据加载完成后的UI操作
mDialog.dismiss();
mTextView.setText("LOAD DATA SUCCESS ");
Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");
}
}
}
进入某个Activity,Activity中需要的数据来自于网络或者其它耗时操作,可以在AsyncTask中onPreExecute完成一些准备操作。
比如上例中显示进度对话框;然后在doInBackground完成耗时操作,
在进行耗时操作时还能不时的通过publishProgress给onProgressUpdate中传递参数,然后在onProgressUpdate中可以进行UI操作。
比如上例更新进度条的进度;当耗时任务执行完成后,最后在onPostExecute进行设置控件数据更新UI等操作,例如隐藏进度对话框。
真正实现就是一个new MyAsyncTask().execute();通过execute方法实现。下面就从源码的角度聊聊AsyncTask。
既然我们调用的是execute方法,那就先从execute方法
@MainThread
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;
}
在执行execute方法中,将status状态更改为running的状态。
mStatus = Status.RUNNING;设置当前AsyncTask的状态为RUNNING,上面的switch也可以看出,每个异步任务在完成前只能执行一次。
onPreExecute();执行了onPreExecute(),当前依然在UI线程,所以我们可以在其中做一些准备工作。
mWorker.mParams = params;将我们传入的参数赋值给了mWorker.mParams
exec.execute(mFuture);
相信大家会对mWorker,mFuture有疑问,别急,容我慢慢道来
private final WorkerRunnable<Params, Result> mWorker;
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
mworker可以看到是Callable的子类,且包含一个mParams用于保存我们传入的参数,
下面看初始化mWorker的代码:
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);
}
};
}
构造方法中我们看到mworker的初始化操作,通过上面的代码我们知道一个抽象类,因此new了一个实现类,实现了call方法,call方法中设置mTaskInvoked=true,且最终调用doInBackground(mParams)方法,并返回Result值作为参数给postResult方法.可以看到我们的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;
}
到此我们看到了一个熟悉的东东,Handler,Handler,Handler,?,重要的事情说三遍。
postResult中出现了我们熟悉的异步消息机制,传递了 message.what为MESSAGE_POST_RESULT的消息;
message.object= new AsyncTaskResult(this,result);
AsyncTaskResult实际上就是一个携带参数的对象而已
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
现在让我们找找handler相关的代码,可以看到,在接收到MESSAGE_POST_RESULT消息时,执行了result.mTask.finish(result.mData[0]);其实就是我们的AsyncTask.this.finish(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;
}
}
}
下面了解下finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
可以看到,如果我们调用了cancel(),则执行onCancelled回调;
正常执行的情况下调用我们的onPostExecute(result);
主要这里的调用是在handler的handleMessage中,所以是在UI线程中。最后将status的状态改为finished。
mworker聊的差不多了,现在我们来聊聊下一个东西mFuture,同样的,mFuture也是在构造方法中完成初始化的
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);
}
}
};
如果mTaskInvoked不为true,则执行postResult; 但是在mWorer初始化时就已经将mTaskInvoked为true,所以一般这个postResult执行不到
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
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;
}
其实执行到最后都是Handler身影的存在。到目前为止都只是介绍了这mWorker和mFuture的实例化而已。
下面说说真正的调用
exec.execute(mFuture);
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
sDefaultExecutor的本质是
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
可以看到sDefaultExecutor其实为SerialExecutor的一个实例,其内部维持一个任务队列;
直接看其execute(Runnable runnable)方法,将runnable放入mTasks队尾; 判断当前mActive是否为空,为空则调用scheduleNext方法 scheduleNext,则直接取出任务队列中的队首任务,如果不为null则传入THREAD_POOL_EXECUTOR进行执行。
看看THREAD_POOL_EXECUTOR是何方神圣?
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
其实就是一个可自定义的线程池。源码中配置的参数如下:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
看到这里,大家就会知道背后原来有一个线程池,且最大支持CPU_COUNT * 2 + 1的线程并发,加上长度为128的阻塞队列,可能会觉得就是在快速调用MAXIMUM_POOL_SIZE+128个以内的AsyncTask子类的execute方法不会出现问题,而大于MAXIMUM_POOL_SIZE+128则会抛出异常。
到此为止,源码分析讲解已经结束,希望大家能对Asynctask有更好的了解。如果你有更好的想法欢迎留言