android 是一个实时系统 ,手机开发对响应速度要求比较高,因为我们在activity或者其实组件里面一般不允许我们有耗时比较长的操作,这样比较容易出现anr,因此如果我们如果有耗时操作比较另起线程(Thread)来完成,线程执行完成后我们往往要刷新界面,但android 刷新UI必须要在主线程里面完成,所以我们必须要用Handler去通信完成。由此我们得出类似网络下载图片显示,我们一般采用的方式:Thread + Handler来实现。不过这样的一种方式有以下几个不好的地方:
1.每次都要为一个任务创建Thread线程,如果任务比较多的话,会创建很多Thread造成资源的浪费。
2.线程执行完成之后就释放没有达到重用的效果,如果我们能使用线程池就不会有这种情况。
3.如果是多个activity的话,每个activity都创建Handler为免太麻烦。
为了解决上面的问题,android还有一种更好的解决方法那就是AsyncTask。
通常使用方式:
MyTask extends AsyncTask<String, Integer, String> {
protected String doInBackground(String... params) {
//耗时操作
}
protected void onPostExecute(String result) {
//完成之后 刷新UI
}
}
这样子的使用方式是非常简单的,我们一起来看一下它的具体实现,
先看一下AsyncTask源码的数据结构:
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());
}
};
这是线程池创建线程的工厂类,每个线程的命名都是AsyncTask # + id号(自增)。
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
线程池阻塞队列,初始大小10 public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
创建线程池。
这里还有另外一个线程池:
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);
}
}
}
这个线程池相对比较简单,主要是把Runable添加到mTasks队列里面。真正执行还是放到THREAD_POOL_EXECUTOR里面去执行,SerialExecutor真正的作用:
1.维护每个Runable添加都是有序的。
2.也起到一个缓存Runable的作用。
我们继续回去到AsyncTask看数据结构:
private static final InternalHandler sHandler = new InternalHandler();创建一个Handler用于刷新界面,这里使用的MQ是主线程的.
接着,看到:
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
WorkerRunnable我们可以叫做工作线程,实现Callable接口。
FutureTask用来获取返回值.
大概的数据结构我们已经看完成了, 再看AsyncTask的构造函数:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
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 occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
构造mWorker工作线程,同时带Result返回值,执行postResult函数的结果;再用mWorker构造一个任务Task.如果运行FutureTask就会执行 call()方法。
我们再来看一下运行方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
直接调用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;
}
设置当前状态->运行:
mStatus = Status.RUNNING;
onPreExecute //执行前做的操作,一般来初始化数据.
exec.execute(mFuture);添加到线程池中运行。注意这里的线程是第二个线程池也就是SerialExecutor,再看一下:SerialExecutor的execute方法,只是把runable封装成新的Runable,然后添加到队列中去,新Runable会在执行完成之后检测队列是否还有Runable,如果有的话,再添加到线程池中运行。第一次mActive是空的,所以就会所Runable添加到线程池中执行。
如果doInBackground运行完成,postResult就会用AsyncTaskResult来封装结果,再用Handler发送Message;
sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result));
进入Handle的handleMessage方法:
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方法,再根据运行结果调用不同的方法,如果运行成功,则调用 onPostExecute(result);刷新UI
到此 AsyncTask我们分析完成了,实现可以概括为:
1.用线程池来对我们创建的任何进行封装,实用线程的重用。
2.利用 Handle来更新UI
注意:以前AsyncTask线程池的运行大小只有5,不过新版本已经改成可以根据cpu的核心来调整。