AsyncTask

AsyncTask是Android提供了一个异步执行的库,它的主要功能是,在UI线程中创建和调用,在后台执行耗时任务,执行任务时或者执行完成后可以更新界面。

基本使用

//AsyncTask<传入参数类型,进度类型,结果类型>,构造函数必须在UI线程中调用
new AsyncTask<Void,Integer,String>(){
    @Override
    protected void onPreExecute() {
        //处于UI线程,在开始执行耗时任务之前调用
    }

    @Override
    protected String doInBackground(Void... params) {
        //处于后台进程,执行耗时任务,返回任务结果
        //do something
        publishProgress(30); // 将会调用 onProgressUpdate
        //do something ...
        publishProgress(100); // 将会调用 onProgressUpdate
        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        //处于UI线程,更新任务进度信息
    }

    @Override
    protected void onPostExecute(String s) {
        //处于UI线程,在doInBackground返回后被调用,用于显示结果信息
    }

    @Override
    protected void onCancelled(String s) {
        //处于UI线程,在调用AsyncTask.cancel()并且doInBackground执行完成之后被调用
        //如果这个函数被调用,将不会调用onPostExecute
    }
}.execute();

实现原理

一切真相都在源码中

//带返回参数的执行体接口,和Runnable类似,只是Runnable是无接口的
public interface Callable<V> {
    V call() throws Exception;
}
//定义WorkerRunnable,增加了一个参数数组mParams
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}
//构造函数(精简了部分代码,只保留关键代码)
public AsyncTask() {
    //这里定义了一个WorkerRunnable,它是一个执行体,将会被投到某个线程中执行
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            //执行耗时任务
            Result result = doInBackground(mParams);
            //返回执行结果
            return postResult(result);
        }
    };

    //使用FutureTask对WorkerRunnable进行再次封装,目的是即使WorkerRunnable没有被执行(没有调用call函数),也可以返回结果(在取消执行的情况下,done会被调用)。
    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
            postResultIfNotInvoked(get());
        }
    };
}

//执行任务,必须在UI线程中调用
public static void execute(Runnable runnable) {
    sDefaultExecutor.execute(runnable);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {
    onPreExecute();
    mWorker.mParams = params;
    exec.execute(mFuture);//将构造函数创建的FutureTask扔到线程中执行
    return this;
}

//接收执行结果,看代码是将结果发送到一个Handler中去了
private Result postResult(Result result) {
    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()); //使用了UI线程的Looper
   }
   public void handleMessage(Message msg) {
       AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
       switch (msg.what) {
           case MESSAGE_POST_RESULT:
               result.mTask.finish(result.mData[0]);//执行完成
               break;
           case MESSAGE_POST_PROGRESS:
               result.mTask.onProgressUpdate(result.mData);//显示进度信息
               break;
       }
   }
}
private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);//调用取消回调函数
    } else {
        onPostExecute(result);//调用结果显示函数
    }
}

分析完源码后,可以总结原理了:先创建一个Callable,将Callable丢到线程中执行,然后将结果发送给Handle处理。

串行OR并行

相信很多Android开发都会发现,默认情况下,多个AsyncTask居然是串行执行的,这个和Thread是完全不一样的,简直是个坑啊!
上面是使用sDefaultExecutor来执行耗时任务的,看下定义:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

显然这是一个串行执行的线程池,所以在app中使用多个asyncTask时,会变成串行执行。。。

简直不能忍,我要换回Thread去!
其实还是有办法的,AsyncTask当然可以并发了,看代码:

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;
//这里定义了一个线程池,最大线程数是CPU_COUNT * 2 + 1
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
//使用方法
new AsyncTask....(){
//...
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

什么? 你跟我说并发数不够? 了解原理的我们分分钟自己创建一个大容量线程池给AsyncTask用。

===============================睡觉线===========================

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值