AsyncTask

本文分析AsyncTask,主要通过源码走一下流程。

先给出API中的一个示例:


    private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {                                                                      
        protected Long doInBackground(URL... urls) {                                                                                                   
            int count = urls.length;                                                                                                                   
            long totalSize = 0;                                                                                                                        
            for (int i = 0; i < count; i++) {                                                                                                          
                totalSize += Downloader.downloadFile(urls[i]);                                                                                         
                publishProgress((int) ((i / (float) count) * 100));                                                                                    
                // Escape early if cancel() is called                                                                                                  
                if (isCancelled()) break;                                                                                                              
            }                                                                                                                                    
            return totalSize;                                                                                                                          
        }                                                                                                                                              
                                                                                                                                                     
        protected void onProgressUpdate(Integer... progress) {                                                                                         
            setProgressPercent(progress[0]);                                                                                                           
        }                                                                                                                                              
                                                                                                                                                     
        protected void onPostExecute(Long result) {                                                                                                    
            showDialog("Downloaded " + result + " bytes");                                                                                             
        }                                                                                                                                              
    }

    new DownloadFilesTask().execute(url1, url2, url3);

Task实例必须在UI线程创建,并在UI线程调用execute方法。

从HONEYCOMB开始,tasks在一个单线程中顺序执行,如果想要并行执行,可以调用executeOnExecutor(java.util.concurrent.Executor, Object[])}。AsyncTask定义了一个线程池:


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

从代码中可以看到,线程池的CorePoolSize大小为2~4。

通常我们是new一个AsyncTask的实例,然后调用它的execute方法。



    private final WorkerRunnable<Params, Result> mWorker;

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {                                                        
        Params[] mParams;                                                                                                                             
    }

    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

    private final FutureTask<Result> mFuture;

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

    @MainThread                                                                                                                                       
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {                                                                      
        return executeOnExecutor(sDefaultExecutor, params);//调用默认的Executor去执行任务                                                                                           
    }

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    

    @MainThread                                                                                                                                       
    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)");//这里可以看到一个task只能被执行一次                                                                                  
            }                                                                                                                                         
        }                                                                                                                                             
                                                                                                                                                      
        mStatus = Status.RUNNING;                                                                                                                     
                                                                                                                                                      
        onPreExecute();//这是一个空方法,可以被子类复写,实现自定义的逻辑                                                                                                                               
                                                                                                                                                      
        mWorker.mParams = params;//将参数传递给mWorker                                                                                                                     
        exec.execute(mFuture);//调用Executor的execute方法,上面看到传过来的是默认的Executor sDefaultExecutor                                                                                                                 
                                                                                                                                                      
        return this;                                                                                                                                  
    }  



    private static class SerialExecutor implements Executor {                                                                                         
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();                                                                               
        Runnable mActive;                                                                                                                             
                                                                                                                                                      
        public synchronized void execute(final Runnable r) {//这里传进来的的是mFuture                                                                                          
            mTasks.offer(new Runnable() {                                                                                                             
                public void run() {                                                                                                                   
                    try {                                                                                                                             
                        r.run();                                                                                                                      
                    } finally {                                                                                                                       
                        scheduleNext();                                                                                                               
                    }                                                                                                                                 
                }                                                                                                                                     
            });//new 一个Runnable并加入队列mTasks                                                                                                                                       
            if (mActive == null) {//第一次这里是null                                                                                                                   
                scheduleNext();                                                                                                                       
            }                                                                                                                                         
        }
        //,第二个AsyncTask调用execute时,把任务加入到mTasks队列,等待上个任务执行完成后,再从队列中poll出来,执行,所以默认情况下,多个AsyncTask是顺序执行的                                                                                                                                             
                                                                                                                                                      
        protected synchronized void scheduleNext() {                                                                                                  
            if ((mActive = mTasks.poll()) != null) {//从队列mTasks中获取刚才加入队列的Runnable并赋值给mActive                                                                                                  
                THREAD_POOL_EXECUTOR.execute(mActive);//调用线程池执行这个Runnable                                                                                                
            }                                                                                                                                         
        }                                                                                                                                             
    }

    

ThreadPoolExecutor.execute方法比较复杂,暂时跳过,我们只要知道


                    try {                                                                                                                             
                        r.run();                                                                                                                      
                    } finally {                                                                                                                       
                        scheduleNext();                                                                                                               
                    }  

这一段代码将会在线程池的某个线程中去执行,这里的r就是mFutrue。


    public class FutureTask<V> implements RunnableFuture<V>

    public interface RunnableFuture<V> extends Runnable, Future<V>

FutureTask实现了RunnableFuture,而RunnableFuture就是Runnable和Futrue的组合(这是多重继承?)。

下面看一下FutrueTask的run方法


        //忽略了部分代码
        try {                                                                                                                                         
            Callable<V> c = callable;//这里的callable就是mWorker                                                                                                              
            if (c != null && state == NEW) {                                                                                                          
                V result;                                                                                                                             
                boolean ran;                                                                                                                          
                try {                                                                                                                                 
                    result = c.call();//mWorker.call()                                                                                                                
                    ran = true;                                                                                                                       
                } catch (Throwable ex) {                                                                                                              
                    result = null;                                                                                                                    
                    ran = false;                                                                                                                      
                    setException(ex);                                                                                                                 
                }                                                                                                                                     
                if (ran)                                                                                                                              
                    set(result);                                                                                                                      
            } 

    protected void set(V v) {                                                                                                                         
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {                                                                           
            outcome = v;                                                                                                                              
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state                                                                           
            finishCompletion();                                                                                                                       
        }                                                                                                                                             
    } 

    private void finishCompletion() {                                                                                                                 
        ......     //忽略部分代码                                                                                                                                       
                                                                                                                                                      
        done(); //这里回调了done方法                                                                                                                                      
                                                                                                                                                      
        callable = null;        // to reduce footprint                                                                                                
    }

所以,mFutrue的run方法简单来说就是调用了mWorker的call方法,如果成功,则再调用done方法。


    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);//这里就回调了doInBackground方法,mParams是在executeOnExecutor方法中赋值的。                                                                                                 
                    Binder.flushPendingCommands();                                                                                                    
                } catch (Throwable tr) {                                                                                                              
                    mCancelled.set(true);                                                                                                             
                    throw tr;                                                                                                                         
                } finally {                                                                                                                           
                    postResult(result);                                                                                                               
                }                                                                                                                                     
                return result;                                                                                                                        
            }                                                                                                                                         
        };

    private Result postResult(Result result) {                                                                                                        
        @SuppressWarnings("unchecked")                                                                                                                
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,                                                                             
                new AsyncTaskResult<Result>(this, result));                                                                                           
        message.sendToTarget();                                                                                                                       
        return result;                                                                                                                                
    }  

        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]);//这里调用了AsyncTask的finish方法,并将doInBackground返回的Result传递给finish方法                                                                                             
                    break;                                                                                                                            
                case MESSAGE_POST_PROGRESS:                                                                                                           
                    result.mTask.onProgressUpdate(result.mData);                                                                                      
                    break;                                                                                                                            
            }                                                                                                                                         
        }

    @SuppressWarnings({"RawUseOfParameterizedType"})                                                                                                  
    private static class AsyncTaskResult<Data> {                                                                                                      
        final AsyncTask mTask;                                                                                                                        
        final Data[] mData;                                                                                                                           
                                                                                                                                                      
        AsyncTaskResult(AsyncTask task, Data... data) {                                                                                               
            mTask = task;                                                                                                                             
            mData = data;                                                                                                                             
        }                                                                                                                                             
    }

    private void finish(Result result) {                                                                                                              
        if (isCancelled()) {//如果已经请求取消,                                                                                                                          
            onCancelled(result);                                                                                                                      
        } else {                                                                                                                                      
            onPostExecute(result);//否则,回调onPostExecute                                                                                                                    
        }                                                                                                                                             
        mStatus = Status.FINISHED;                                                                                                                    
    }

然后,继续mFutrue的run方法,会回调它的done方法。


        mFuture = new FutureTask<Result>(mWorker) {                                                                                                   
            @Override                                                                                                                                 
            protected void done() {                                                                                                                   
                try {                                                                                                                                 
                    postResultIfNotInvoked(get());//这里调用Future的get方法,与set对应,拿到Result(细节较复杂)                                                                                                    
                } 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) {//如果mWorker的的call方法没有执行                                                                                                                        
            postResult(result);                                                                                                                       
        }                                                                                                                                             
    } 

最后scheduleNext(),如果有其他任务在队列中,就poll出任务并执行。

简单总结一下,在主线程调用execute会回调onPreExecute,然后在线程池中通过mWorker回调doInBackground,
最后通过handler发送消息给主线程,在主线程回调onPostExecute。


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

在doInBackground中调用publishProgress,实际也是通过Handler将消息发送到主线程,在主线程回调onProgressUpdate


            case MESSAGE_POST_PROGRESS:                                                                                                           
                    result.mTask.onProgressUpdate(result.mData);                                                                                      
                    break; 

AsyncTask提供了cancel方法


    public final boolean cancel(boolean mayInterruptIfRunning) {                                                                                      
        mCancelled.set(true);//设置为true, isCancelled将返回true                                                                                                                        
        return mFuture.cancel(mayInterruptIfRunning);                                                                                                 
    }

FutrueTask的cancel方法,部分代码


        try {    // in case call to interrupt throws exception                                                                                        
            if (mayInterruptIfRunning) {                                                                                                              
                try {                                                                                                                                 
                    Thread t = runner;                                                                                                                
                    if (t != null)                                                                                                                    
                        t.interrupt();//调用Thread的interrupt方法                                                                                                             
                } finally { // final state                                                                                                            
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);                                                                             
                }                                                                                                                                     
            }                                                                                                                                         
        } finally {                                                                                                                                   
            finishCompletion();                                                                                                                       
        }

如果需要让多个Task并行执行,可以调用executeOnExecutor,并将THREAD_POOL_EXECUTOR作为参数传入。

关于线程池相关的内容,将在后续整理。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • Android Handler机制系列文章整体内容如下: Android Handler机制1之ThreadAnd...
    隔壁老李头阅读 3,191评论 1 15
  • 由于从wordpress将文章倒回,发现格式有点混乱,经努力调整后依然有部分的格式还未调教好,请多多包涵. 分析A...
    walker_lee0707阅读 1,197评论 3 51
  • Android开发者:你真的会用AsyncTask吗? 导读.1 在Android应用开发中,我们需要时刻注意保证...
    cxm11阅读 2,703评论 0 29
  • 前言:最近的目标就是跳槽,跳槽完再搭个站,这样的话生活就充实一点点了吧。 今天说的AsyncTask也是项目中常常...
    黑白咖阅读 513评论 0 3
  • 岁月的歌唱响 你听 是风在低吟 碎在掌心里的皱褶 鲜活着 在跳动 平凡是最矛盾的形容词 孕育自由 仍割舍不掉梦想 ...
    萧北笙烟阅读 156评论 1 2