标签:
在Android开发中,我们进行异步处理一般会采用两种方式:
1.Thread +Handler
通常我们在Thread里面发送消息,然后在Handler的handleMessage方法里面去处理对应的任务,因为Android是不允许UI线程去更新UI的,这个时候我们可以采取这种方式
2.AsyncTask
AsyncTask是Android为我们封装的一个轻量级的异步处理框架,其实底层也是用了类似Thread+Handler的方式。对外提供了一些方法,我们实现这些方法就可以很方便的进行异步处理了。
既然两种方式都可以实现异步处理任务,那么有什么区别呢?该使用哪个呢?
1.AsyncTask实现的原理和适用的优缺点
AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
使用的优点:
简单,快捷
过程可控
使用的缺点:
在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
2.Handler异步实现的原理和适用的优缺点
在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)运行并生成Message-Looper获取Message并 传递给HandlerHandler逐个获取Looper中的Message,并进行UI变更。
使用的优点:
结构清晰,功能定义明确
对于多个后台任务时,简单,清晰
使用的缺点:
在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)
综上所述:
数据简单使用AsyncTask:实现代码简单,数据量多且复杂使用handler+thread :相比较
AsyncTask来说能更好的利用系统资源且高效 .AsyncTask其实是Android给开发者提供的
一个简单轻量级的多线程类,通过它我们可以很容易新建一个线程做一些耗时的操作,并在
这个过程中更 新UI。之所以说它轻量级,是因为缺少了直接使用Thread的灵活性。如果是
很复杂的操作,还是建议通过Thread来操作,然后通过 Broadcast的方式来更新UI。
好了,看了两种方式的区别,我们进入今天的重点,AsyncTask源码的分析。
我们平时会这样使用AsyncTask,
1.创建一个类继承AyncTask(因为AsyncTask是抽象的)
class MyTask extends AsyncTask<Integer,String,String>{
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(Integer[] params) {
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
这里讲解两个地方:
(1)参数
我们看到AsyncTask有三个泛型,Params,Progress,Result,这里分别为Integer,String,String,每个泛型代表的意思如下
Params:异步任务执行需要传入的参数类型
Progress:异步任务执行过程中返回进度值的类型
Result:异步任务执行结束后返回结果的类型
(2)方法
这里我们重写了三个最常用的方法
onPreExecute:异步任务开始之前做一些初始化的动作,比如初始化进度条,AsyncTask实例创建在哪个线程,这个方法执行在哪个线程
doInBackground:执行后台任务的方法,运行在子线程
onPostExecute:异步任务结束后调用的方法,运行在主线程,通常用来处理结果。
2.执行任务
调用如下方法使异步任务开始执行
//创建AsyncTask对象,调用execute方法
new MyTask().execute();
public abstract class AsyncTask<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTask";
//获得当前CPU的核心数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//当前线程池容量 = CPU核心数+1
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//最大线程池容量 = CPU核心数*2+1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//当前线程数量大于核心线程数量时,空闲线程在执行任务前等待的最大时间,超过此时间如果还没有任务则会被终止
private static final int KEEP_ALIVE = 1;
//创建新线程需要的线程工厂,需要作为参数传递到ThreadPoolExecutor的构造函数中
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
//使用Runnable对象创建线程对象并指定名称
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());//AsyncTask #1
}
};
//用来保存任务的工作队列,需要作为参数传递到ThreadPoolExecutor的构造函数中,此处采用阻塞队列,遵循FIFO,容量为128,也就是说最多存储128个任务
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
//根据上面的参数创建线程执行器
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
//顺序执行任务的Executor
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//发送结果的消息
private static final int MESSAGE_POST_RESULT = 0x1;
//发送进度的消息
private static final int MESSAGE_POST_PROGRESS = 0x2;
//默认使用顺序执行器
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//用来发送消息的InternalHandler
private static InternalHandler sHandler;
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
//默认挂起状态,等待任务执行
private volatile Status mStatus = Status.PENDING;
//是否取消标志
private final AtomicBoolean mCancelled = new AtomicBoolean();
//异步任务对象是否创建标志
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
//串行任务执行器的实现,取出一个个任务交给上面的线程执行器执行
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);
}
}
}
//当前任务的状态
public enum Status {
PENDING,//挂起,等待执行
RUNNING,//正在运行
FINISHED,//执行结束
}
//获得InternalHandler对象
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
/** 隐藏方法*/
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
//创建WorkerRunnable对象,继承自Callable,重写call方法
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
//设置线程优先级Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//调用doInBackground,传入我们的输入参数
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
//调用postResult方法,传入doInBackground的结果
return postResult(result);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
//任务执行完毕调用此方法
protected void done() {
try {
//如果没有传递任务则进行传递,get方法为获取FutureTask执行完毕的结果
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);
}
}
};
}
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;
}
这个方法是干啥的呢?将doInBackground处理的结果封装成一个AsyncTaskResult对象发送给自定义的Handle对象进行处理,我们可以看到这里有一个getHandler方法
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
采用了同步锁的方法来获取InternalHandler对象,这个Handler对象就是用来处理消息的,我们待会分析,获得Handler对象后,我们发送了一个msg.obj为如下的消息
new AsyncTaskResult<Result>(this, result)
我们去看看这个类
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
这个类很简单,有两个成员变量,代表当前任务的AsyncTask对象,这里为this,然后就是数据Data,这里我们传递过来的是doInBackground的处理结果。既然消息发送了,我们看看是如何处理的吧
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;
}
}
}
上面先获取到了发送过来的消息,然后根据消息的类型进行了判断,进行了不同的处理,如果是投递结果的消息,执行下面的操作
result.mTask.finish(result.mData[0]);
result.mTask就是当前的任务,然后调用了finish方法,我们去看看
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
很简单,首先判断当前任务是否取消了,如果取消了,就调用onCancelled方法,定义如下
protected void onCancelled(Result result) {
onCancelled();
}
当任务取消的时候会回调onCancelled方法,所以如果我们想要在任务取消的时候做一些操作,可以重写这个方法。
如果没有取消,则执行onPostExecute方法,传入我们的结果,最后将当前任务状态设置为完成,这里调用了onPostExecute方法,
至此,我们已经看到了doInbackground和onPostExecute方法的调用之处,那么还剩下一个onPreExcute方法怎么没看到啊?因为我们到目前为止只分析了创建任务实例这个过程所发生的事,任务还没执行执行呢。
执行任务我们会调用execute方法,如果必要的话会传入参数
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
这里又调用了executeOnExecutor方法,传入了sDefaultExecutor和我们的参数,大家还记得sDefaultExecutor是什么吗?懒得向上找了,再给大家贴出来吧
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
就是串行执行器,我们去看看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;
}
首先判断当前状态,前提是不是挂起状态,如果正在执行或者已经执行完毕,我们再次调用execute方法就会抛出异常,接下来将当前状态标记为正在执行,然后调用onPreExecute方法,这里我们终于看到onPreExecute方法被调用了,然后将我们执行任务时传入的参数赋值给mWorker的mParams,这个mWorker是啥,之前说过了,
private final WorkerRunnable<Params, Result> mWorker;
最后调用sDefaultExecutor 的execute执行任务,并且传入我们的FutureTask对象。至此,整个过程就完了。
接下来讲一些细节性的东西,可能大家也发现有些地方还没有分析
1.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);
}
}
}
首先创建了一个ArrayDeque对象,用来接收我们的消息,然后调用了此对象的offer方法,再里面调用了execute参数中Runnable对象的run方法,那么这个Runnable对象是啥啊,如果你仔细阅读了上面的内容,就会发现这个Runnable对象就是FutureTask,为什么FutureTask能转换为Runnable呢,
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture extends Runnable, Future {
明白了吧,废话我就不说了,
那么我们就去看看FutureTask的run方法
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
.....
只讲重点,这里将一个callable对象赋值给了一个新的对象,然后调用了call方法,我们看看这个callable对象是在哪里赋值的
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
是在FutureTask构造方法里面复制的,到这大家是不是想起什么了,是的,我们再AsyncTask中创建锅Callable的实现类WorkerRunnable并且将其传给了FutureTask的构造函数,所以,当我们最终调用sDefaultExecutor 的execute方法的时候,就执行了WorkerRunnable中的call方法,call中又调用doInbackground,然后postResult发送消息,又回到了上面的分析。
run执行完毕之后,会判断mActive是否为空,第一次肯定为空,执行scheduleNext方法
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
调用了mTasks的poll方法从当前队列头部取出消息,给线程执行器执行,以后mActive就不为null,我们可以看到scheduleNext放到了finally方法里面,保证了每次都会执行。
好了,AsyncTask的源码就分析到这里了,已经快吐血了,费了不少时间,脑子现在还是有点乱,最后大概总结一下下面这句话都干了啥
new MyTask().execute();
1.创建对象(new MyTask())
创建WorkerRunnable对象(Callable),重写call方法—->将WorkerRunnable传递给FutureTask
2.执行任务(execute())
execute(Params… params)—->executeOnExecutor(Executor exec,
Params… params) —->调用onPreExecute—->调用SerialExecutor的execute方法,传入上面的FutureTask对象,请注意,这个FutureTask包装了WorkerRunnable对象,可不简单哦—->调用FutureTask的run方法(run方法里面调用了call)—->调用WorkerRunnable的call方法—->调用scheduleNext执行下个任务
最后说一下AsyncTask版本上的差异
在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务
那么我们现在有没有办法让AsyncTask并行执行呢》有
在Anddroid3.0以后的AsyncTask类给暴露出一个接口也就是上面的executeOnExecutor方法啦,我们只需要重新构造一个线程池执行器,比如说你可以调用newCachedThreadPool方法来创建一个无线大的缓存线程池,可以同时执行无线个任务。
//构建一个缓存线程池,用于同时执行无限多个异步耗时任务
ExecutorService executorService = Executors.newCachedThreadPool();
asyncTask.executeOnExecutor(executorService,params);
开发者可以根据项目需求选择自己合适的线程池执行器:
Single Thread Executor : 只有一个线程的线程池,因此所有提交的任务是顺序执行,代码: Executors.newSingleThreadExecutor()
Cached Thread Pool : 线程池里有很多线程需要同时执行,老的可用线程将被新的任务触发重新执行,如果线程超过60秒内没执行,那么将被终
止并从池中删除,代码:Executors.newCachedThreadPool()
Fixed Thread Pool : 拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待,代码: Executors.newFixedThreadPool()
Scheduled Thread Pool : 用来调度即将执行的任务的线程池,代码:Executors.newScheduledThreadPool()
Single Thread Scheduled Pool : 只有一个线程,用来调度执行将来的任务,代码:Executors.newSingleThreadScheduledExecutor()
标签:
原文地址:http://blog.csdn.net/small_lee/article/details/51297308