Android之AsyncTask源码学习

159 阅读6分钟

AsyncTask

1.定义,介绍:

  • asynctask是Android中的一个自带的轻量级异步类,通过他可以轻松的实现工作线程和UI线程之间的通信和线程切换(其实也只能在工作和ui线程之间切换,稍后会提到)
  • asynctask是一个抽象类,所以我们需要创建他的子类,一般重写他的四个方法即可:
//这个就是要在后台做的工作,他将运行在后台工作线程上
@WorkerThread
protected abstract Result doInBackground(Params... params);

//这个时开始执行前的操作,运行在主线程上
@MainThread
protected void onPreExecute() ;

//doInBackground完成后调用
@MainThread
protected void onPostExecute(Result result) 

//实时更新,通过在doInBackground中调用publishProgress()方法
@MainThread
protected void onProgressUpdate(Progress... values) 

2.源码

1.创建:

  • 问题:为什么说只能在工作线程和UI线程之间通信?我自己建一个looper线程也不行吗?(当然这种情况也很少) 看他的三个构造函数:
 public AsyncTask() {
        this((Looper) null);
    }

/**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
public AsyncTask(@Nullable Handler handler) {
        this(handler != null ? handler.getLooper() : null);
}

 /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
 public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);  

            ...
            ...
            ...
    }

可以看出不管调用哪个都会指向第三个构造方法,关键代码
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper);
所以,如果调用第一个构造函数,那么传入的Looper为null;如果调用第二个则传入handler.getLooper(),如果他为MainLooper的话,也将和第一个构造函数一样进入了 getMainHandler()方法:创建了一个拥有主线程的InternalHandler

 private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

 private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

        @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;
            }
        }
    }

那如果他不是mainlooper的话,就创建了一个new Handler(callbackLooper),然而这个handle既没有传入callback,也没有重写其handleMessage方法,其实是一个空的handle,但他可以调用msg的callback呀。就算这样,那我是不是仍然可以创建一个不与主线程(UI线程)相连的handle,那为啥还说只能用在ui与工作线程之前呢?
哈哈,请再看一下上面贴上的三个构造函数的源码,我专门把第二个和第三个的注释也贴了上去,有一个很重要的注解@hide,也就是说google把第二个和第三个构造函数给隐藏起来了,不对开发者开放,我们根本访问不到(虽然能看到,而且时public,感兴趣可以查一下这个注解)。所以我们只能用第一个构造函数,传入空的looper,从而调用getMainHandler();

  • 顺便提一下handle 的执行顺序(dispatchMessage)
    1. msg的callback不为空,调用handleCallback方法(message.callback.run())
    2. mCallback不为空,调用mCallback.handleMessage(msg)
    3. 最后如果其他都为空,执行Handler自身的 handleMessage(msg) 方法

2.执行:

  • 包装doInBackground方法。 创建完handle后,在第三个构造函数中可以看出,他接着创建了work(实现了callable)和futur(FutureTask对象其实就是更方便操作线程,Futrue可以监视目标线程调用call的情况,当你调用Future的get()方法以获得结果时,当前线程就开始阻塞,直接call方法结束返回结果。)其中很关键的代码就是在work中调用了,然后又将work用futuretask封装,在之后的调用中会最后提交给线程池
    result = doInBackground(mParams);
    mFuture = new FutureTask<Result>(mWorker) {......}
mWorker = new WorkerRunnable<Params, Result>() {
           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;
           }
       };

最后在finaly里调用postResult(result),将结果传递给handle,将调用handle(InternalHandler)的handleMessage,他处理两个,一个是执行结束finish(),从而调用了onPostExecute,另一个是在doInBackground里用户调用的publishProgress像handle发送消息,从而调用onProgressUpdate

 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;
            }
        }

        protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

     private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

asynctask的两个线程池:

- `public static final Executor THREAD_POOL_EXECUTOR`:
 private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);


    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

可以看出,这是一个核心线程数最小为2的线程池,它是用来并行执行task的,但当达到核心线程最大值后,依旧会在阻塞队列里等待

  • 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);
           }
       }
   }

所以第二个 是一个顺序串行执行的Executor:每次将任务提交到数组双向队列里,execute后会依次执行,然后scheduleNext获取下一个任务。

  • AsyncTask中默认时使用的第二个,SERIAL_EXECUTOR,串行执行,
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; 当然你也可以修改
/** @hide */
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

然而很不幸,他也被hide起来了...但是可以在接下来的入口处,直接调用executeOnExecutor(Executor exec,Params... params)方法传入指定的Executor

开始执行的入口:

当创建完asynctask后,调用asynctask.execute(Params... params)就可开始执行,然后其实是调用了executeOnExecutor(Executor exec,Params... params)这个方法(所以其实你也可以调用这个executeOnExecutor方法并且指定你Executor),传入 sDefaultExecutor和doInbackgroud方法的参数:

 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;
    }

四个回调执行的线程

- `onPreExecute()`:

从上面代码我们可以看到在这里执行了 onPreExecute(),所以,在哪个线程执行了asynctask.execute(Params... params), onPreExecute()他就在哪个线程执行
- doInBackGround():被放到了asynctask的线程池里执行
- onProgressUpdate()和onPostExecute()这两个都是在handler的回调handleMessage里被调用的,所以关键就在handler里的Looper是哪个线程的,他们俩就在哪个线程执行(注意,这里其实跟handler在哪个线程创建没关系,可以在子线程创建handler而传入主线程的Looper)而我们之前也分析了,现在handler的looper只能是主线程的 ,所以这两个方法也是在主线程执行的 如:

 Handler handler=new Handler(getMainLooper(), new Handler.Callback() {
                    @Override
                    public boolean handleMessage(Message msg) {
                        Log.i(TAG, "handleMessage: "+Thread.currentThread());
                        titleBar.setTitle("hahahah");
                        return false;
                    }
                });

下面是我的测试例子:


public class AsyncTest extends AsyncTask<String,Integer,String> {
    public static final String TAG="AsyncTask";

    public AsyncTest(){
        super();
    }
    @Override
    protected String doInBackground(String... strings) {
        Log.i(TAG, "doinbackground: "+Thread.currentThread()+strings);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        publishProgress(2);

        return "finish";
    }

    @Override
    protected void onPreExecute() {
        Log.i(TAG, "onPreExecute: start");
        Log.i(TAG, "onPreExecute: "+Thread.currentThread());
    }

    @Override
    protected void onPostExecute(String s) {
        Log.i(TAG, "onPostExecute: "+s);
        Log.i(TAG, "onpostexecute: "+Thread.currentThread());

    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        Log.i(TAG, "onProgressUpdate: "+values[0]);
        Log.i(TAG, "onprogressupdate: "+Thread.currentThread());

    }
}
Activity里:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.acitivty_view_test);

        new Thread(new Runnable() {
            @Override
            public void run() {
               AsyncTest test=new AsyncTest();
               test.execute("aaa");
            }
        }).start();

    }

结果:

asynctask.png
所以,asynctask也不一定非得在主线程创建和执行