AsyncTask源码分析

作者: 程序员徐公 | 来源:发表于2017-02-28 19:58 被阅读1066次

    前言

    IntentService使用及源码分析

    HandlerThread源码分析

    AsyncTask使用及封装实践

    AsyncTask源码分析

    上一篇博客,AsyncTask使用及封装实践 我们主要介绍了AsyncTask 的使用及封装实践,这一篇博客我们主要来讲解AsyncTask的源码


    这篇博客主要讲解以下内容

    • AsyncTask的几个主要方法讲解
    • AsyncTask 的源码分析
    • AsyncTask怎样使用自定义的Executor

    AsyncTask的几个主要方法讲解

    讲解之前我们先来回顾一下AsyncTask的几个主要方法

    • Void onPreExecute()

    在task 任务开始执行的时候调用,在doInBackground(Params... params)方法之前调用,在主线程中执行

    • Result doInBackground(Params... params)

    主要用来执行耗时操作,在子线程中执行,Params为我们参数的类型。而Result这个泛型,是我们返回的类型(可以是Integer,Long,String等等类型,只要不是八种基本类型就OK),同时 Result 的类型将作为 onPostExecute(Result result)的参数。

    • Void onProgressUpdate(Progress... values)

    Runs on the UI thread after publishProgress(Progress...) is invoked. 当我们调用 publishProgress()方法的时候,会调用 onProgressUpdate()这个方法

    • Void onPostExecute(Result result)
      在doInBackground()方法执行完毕之后,会调用这个方法,是在主线程中执行的。但如果我们手动调用了cancelled()方法,那么这个方法将不会被调用。

    • void onCancelled()

    在Task

    • execute(Params... params)

    Executes the task with the specified parameters.当我们调用这个方法的时候,会执行任务

    • executeOnExecutor(Executor exec, Params... params)

    在指定的线程池里面执行Task

    需要注意的是,Params,Progress,Result 并不是一种特定的类型,它其实是泛型,它支持除了八种基本类型之外的类型,跟普通的泛型一样。


    AsyncTask 的源码分析

    执行流程

    当我们调用 execute()方法的时候,会紧接着调用我们的execeteOnExecutor(sDefaultExecutor, params)方法
    在这个方法里面,会首先判断执行的状态的合法性,如果是finish或者running,会抛出异常,这也就是为什么AsyncTak只能被调用执行一次。紧接着会调用onPreExecute()方法

    
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    
    
    
    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;
    }
    

    接着会把当前的状态设置running状态,并把我们的params传递给我们的mWork。params=params;

    那这个mWork是什么呢?

    public AsyncTask() {
        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;
            }
        };
    
        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);
                }
            }
        };
    }
    
    • 我们先来分析一下mWorker;

    mWorker为AsyncTask的一个内部类
    ,实现了Callable接口,在call方法里面会调用我们的doInBackground方法,这也就是为什么我们的doInBackground。方法是在子线程里面执行的,执行完doInBackground()方法会把结构传递给我们的postResult(result)方法,在result方法,会调用handler发送消息,
    接着再handler的handleMessage里面处理,在handleMessage里面,又会调用我们的 finish()方法,finish()方法里面会判断任务是否取消,如果被取消,会调用onCancelled(),否则会调用onPostExecute()方法。

    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;
            }
        }
    }
    
    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
    
    
    
    • 接着我们来分析一下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);
                }
            }
        };
    
    1. postResultIfNotInvoked(get());get()表示获取mWorker的call的返回值,即Result。

    2. 然后看postResultIfNotInvoked方法。会判断是否已经将结果发送出去,即判断在mWork里面是否已经调用postResult(result)发送结果,没有的话调用再调用postResult(result)发送出去

    private void postResultIfNotInvoked(Result result) {
            final boolean wasTaskInvoked = mTaskInvoked.get();
            if (!wasTaskInvoked) {
                postResult(result);
            }
        }
    

    还记得上面exec.execute()吗?exec为executeOnExecutor(sDefaultExecutor,params)中的sDefaultExecutor

    下面看这个sDefaultExecutor

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;  
    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);  
                }  
            }  
    }
    

    可以看到sDefaultExecutor其实为SerialExecutor的一个实例,其内部维持一个任务队列;直接看其execute(Runnable runnable)方法,将runnable放入mTasks队尾;
    判断当前mActive是否为空,为空则调用scheduleNext方法

    scheduleNext方法里面,则直接取出任务队列中的队首任务,如果不为null则传入THREAD_POOL_EXECUTOR进行执行。

    下面看THREAD_POOL_EXECUTOR为何方神圣:

    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 CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;
    
    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);
    
    
    

    回顾一下sDefaultExecutor,真正在execute()中调用的为sDefaultExecutor.execute:

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

    可以看到,如果此时有10个任务同时调用execute(s synchronized)方法,第一个任务入队,然后在mActive = mTasks.poll()) != null被取出,并且赋值给mActivte,然后交给线程池去执行。然后第二个任务入队,但是此时mActive并不为null,并不会执行scheduleNext();所以如果第一个任务比较慢,10个任务都会进入队列等待;

    真正执行下一个任务的时机是,线程池执行完成第一个任务以后,调用Runnable中的finally代码块中的scheduleNext,所以虽然内部有一个线程池,其实调用的过程还是线性的。一个接着一个的执行,相当于单线程。

    publicProgress()方法的分析

    这也就是我们在Result doInBackground(Params... params)方法里面调用 publishProgress()方法,会回调onProgressUpdate的原因

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

    AsyncTask怎样使用自定义的Executor

    常用的集中线程池介绍

    • newCachedThreadPool()

    缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse.如果没有,就建一个新的线程加入池中。能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。缓存型池子通常用于执行一些生存期很短的异步型任务 。

    • newFixedThreadPool()

    fixedThreadPool与cacheThreadPool差不多,也是能reuse就用,但不能随时建新的线程 其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子。和cacheThreadPool不同:fixedThreadPool池线程数固定,但是0秒IDLE(无IDLE)。这也就意味着创建的线程会一直存在。所以fixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器。

    • newScheduledThreadPool()

    调度型线程池。这个池子里的线程可以按schedule依次delay执行,或周期执行 。0秒IDLE(无IDLE)。

    • SingleThreadExecutor

    单例线程,任意时间池中只能有一个线程 。用的是和cache池和fixed池相同的底层池,但线程数目是1-1,0秒IDLE(无IDLE)。

    使用

    // 调用 executeOnExecutor,传入相应的线程池即可。
    mDownloadTask.executeOnExecutor(Executors.newFixedThreadPool(4));
    

    IntentService使用及源码分析

    HandlerThread源码分析

    AsyncTask使用及封装实践

    AsyncTask源码分析

    相关文章

      网友评论

        本文标题:AsyncTask源码分析

        本文链接:https://www.haomeiwen.com/subject/gjhfgttx.html