android 線程研究一(AsyncTask源碼深度剖析)

在研究AsyncTask源碼之前,我們先通過一個例子來了解一下AsyncTask的用法,看其有哪些方法。

public class AsynActivity extends Activity implements OnClickListener{

	Button btn;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_asyn);
		
		btn = (Button)findViewById(R.id.asyn);
		btn.setOnClickListener(this);
	}
	
	@Override
	public void onClick(View view) {
		TestAsyn asyn = new TestAsyn();
		asyn.execute();
		
		//asyn.cancel(true);		
		Log.i("AsynActivity", String.valueOf(asyn.isCancelled()));
	}	
	class TestAsyn extends AsyncTask<Void, Void, Result>{	
		@Override
		protected void onPreExecute() {
			Log.i("TestAsyn", "onPreExecute");
			super.onPreExecute();
		}
		
		@Override
		protected Result doInBackground(Void... params) {
			Log.i("TestAsyn", "doInBackground");			
			//publishProgress(params);
			//cancel(true);
			return null;
		}
		
		@Override
		protected void onPostExecute(Result result) {
			Log.i("TestAsyn", "onPostExecute");
			super.onPostExecute(result);
		}
		
		@Override
		protected void onProgressUpdate(Void... values) {
			Log.i("TestAsyn", "onProgressUpdate");
			super.onProgressUpdate(values);
		}
		
		@Override
		protected void onCancelled() {
			Log.i("TestAsyn", "onCancelled");
			super.onCancelled();
		}
		
		@Override
		protected void onCancelled(Result result) {
			Log.i("TestAsyn", "onCancelled");
			super.onCancelled(result);
		}	
	}	
}
運行結果:


從結果我們可以看出,在調用execute()後,首先執行的是onPreExecute,然後是doInBackground,最後是onPostExecute方法,這三個方法在調用execute

之後會自動執行。然後我們將onClick方法中的cancel()註釋去掉,運行結果輸出:


從結果我們可以知道,在調用cancel()方法之後,所有未被執行的方法都不會被執行了,如果doInBackground沒有被執行,那麼doInBackground和

onPostExecute都不會被執行了。如果doInBackground已經被執行了,onPostExecute還未被執行,那麼onPostExecute還會被被執行嗎?要驗證一

下就在doInBackground方法中調用cancel()方法,執行的結果就是onPostExecute方法沒有輸出,也就是其沒有被執行。從上面這個結果中我們還知

道,在調用cancel()方法後,兩個onCancelled()方法都會被執行。

有沒有發現onProgressUpdate方法一直都沒有執行,爲什麼呢?因爲需要在doInBackground方法中調用publishProgress方法,調用這個方法之後

onProgressUpdate方法就會自動被執行。你可以將這個例子中的publishProgress前的註釋去掉,然後運行就會發現onProgressUpdate方法就被執

行了。

使用知道以後,下面我們就來分析一下他的源碼:我取出了源碼中的一些無用的方法以及註釋,剩下了210行左右的代碼,下面我將整個代碼貼出來

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";

    private static final int CORE_POOL_SIZE = 5;
    private static final int MAXIMUM_POOL_SIZE = 128;
    private static final int KEEP_ALIVE = 1;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);//原子類,消除synchronized關鍵字       
        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };//創建線程工廠對象

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(10);//同步隊列

    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 MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    //定義handler,他的實現也使用了handler額
    private static final InternalHandler sHandler = new InternalHandler();
    private static volatile Executor sDefaultExecutor = new SerialExecutor();
    
    private final WorkerRunnable<Params, Result> mWorker;//定義Callable接口對象,執行結果的返回就跟這個對象的屬性有關
    private final FutureTask<Result> mFuture;//定義FutureTask對象
    
    public enum Status {PENDING,RUNNING,FINISHED,}//枚舉對象,3種狀態
    private volatile Status mStatus = Status.PENDING; //初始化狀態爲pending 
    
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();//原子對象

    //構造方法
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);               
                return postResult(doInBackground(mParams));
            }
        };//創建Callable接口對象
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    final Result result = get();
                    postResultIfNotInvoked(result);
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occured while executing doInBackground()",e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                } catch (Throwable t) {
                    throw new RuntimeException("An error occured while executing doInBackground()", t);
                }
            }
        };//將Callable接口對象mWorker作爲參數傳遞給FutureTask,這些都是java類庫中的一些基本使用,不瞭解的好好把Java編程思想看完
    }

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }
    private Result postResult(Result result) {
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
    
    //AsyncTask類中能夠被重寫的方法
    protected abstract Result doInBackground(Params... params);
    protected void onPreExecute() {}
    @SuppressWarnings({"UnusedDeclaration"})
    protected void onPostExecute(Result result) {}
    @SuppressWarnings({"UnusedDeclaration"})
    protected void onProgressUpdate(Progress... values) {}
    @SuppressWarnings({"UnusedParameters"})
    protected void onCancelled(Result result) {
        onCancelled();
    }    
    protected void onCancelled() {}
    
    //下面這些方法都不能夠被重載,因爲是final類型的。
    public final boolean isCancelled() {
        return mFuture.isCancelled();
    }
    public final boolean cancel(boolean mayInterruptIfRunning) {
        return mFuture.cancel(mayInterruptIfRunning);
    }
    public final Result get() throws InterruptedException, ExecutionException {
        return mFuture.get();
    }
    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
            ExecutionException, TimeoutException {
        return mFuture.get(timeout, unit);
    }
    
    //AsyncTask調用的三個方法,
    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("");
                case FINISHED:
                    throw new IllegalStateException("");
            }
        }
        mStatus = Status.RUNNING;
        onPreExecute();
        mWorker.mParams = params;
        exec.execute(mFuture);     
        return this;
    }//看見沒第一個方法調用其實也是executeOnExecutor,那爲什麼不直接調用呢?因爲在這個方法中我們可以自定義線程執行器Executor
    public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }
    
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            sHandler.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;
    }

    private static class InternalHandler extends Handler {
        @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;
            }
        }
    }
    @SuppressWarnings({"RawUseOfParameterizedType"})
    private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }  
    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }    
    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();//真正執行Callable中run方法的地方
                    } finally {
                        scheduleNext();
                    }
                }
            });//新建一個Runnable對象,在run方法中執行參數Runnable對象的run方法,然後將其放入數組雙端隊列mTasks中
            if (mActive == null) {
                scheduleNext();
            }
        }
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);//將任務添加到線程池中
            }
        }
    }
}

上面就是AsyncTask類全部代碼,其他無用的代碼和註釋被我去掉了。我的版本爲4.03。下面我們就來根據執行的順序來進行源碼分析。

一、從上面代碼我們知道,創建AsyncTask對象時,會創建一個ThreadPoolExecutor的線程池,那些隊列,線程工廠都是作爲參數傳遞

給這個線程池的,所以不用管,你只要知道這個線程池的相關知識就行。

二、創建了一個枚舉類型Status,其中具有3種狀態,聲明瞭一個枚舉對象mStatus,並初始化狀態爲PENDING。

三、創建了Handler,以及一個默認的線程執行器sDefaultExecutor,之所以爲默認,那就證明其實這個線程執行器我們自己可以自定義的

。嗯,所有的準備工作做好了,接下來我們就來看構造方法。

在構造方法中,實例化了mWorker對象和mFuture對象,在mWoker實例中的call方法中,我們可以看到doInBackground方法就是在這裏

被調用的,從這裏我們可以看出doInBackground方法其實是在子線程中被執行的。mFuture在實例化過程中,mWoker作爲參數傳入,並

且mFuture重寫了done()方法,通過查看Java API可以知道,這個方法主要用來查詢Task是否被取消,在這裏獲取查詢的結果。

這樣構造方法就分析完全了,對象初始化就完成了。接下來我們根據調用步驟來進行分析。

一、從上面的實例中我們可以知道,AsyncTask類有三個啓動方法,從源碼中我們可以知道這三個方法的差異:

1、execute(Params... params) 這個方法其實調用就是第二個方法。

2、executeOnExecutor 既然第一個方法調用是第二個方法,爲什麼不將這兩個方法和爲一個方法,理由就是:第一個方法不能自定義線程

執行器,而第二個方法能夠自定義線程執行器。

3、execute(Runnable runnable)。這個方法就是自定義子線程,源碼提供的mFuture,以及mWoker對象都無用了,這些東西都要自己去實

現,但是使用的還是源碼默認的線程執行器。

那些需要自定義的方法我就不進行分析了,主要分析系統默認調用的方法,所以我們現在拿第一個方法爲引導來進行逐步分析。


步驟分析:

步驟一、execute()方法調用後,將默認的線程執行器對象sDefaultExecutor傳入了進去,調用executeOnExecutor方法,查看

executeOnExecutor方法。

步驟二、在executeOnExecutor方法中,首先對任務的狀態進行了判斷,如果不是初始狀態則拋出異常,這證明execute()方法只能被執行一次

多次執行則無效。判斷之後將任務狀態設置爲RUNNING態,執行onPreExecute()方法,從這裏可以看出來,onPreExecute()方法其實還是在

主線程中被執行的,他並沒有放到子線程中去執行。然後調用線程執行器將任務對象mFuture進行提交。

步驟三、查看任務執行器的實行類SerialExecutor,從源碼中我們可以看到,首先創建一個雙端隊列數組mTasks,提交一個Runnable對象放

到這個隊列中,並且將任務放到這個Runnable對象的run方法中來執行。提交到mTasks中後,再從隊列中取出,將取出的放入到線程池中進

行執行。這樣任務就開始執行了。

步驟四、任務開始執行後,在線程池中執行的是doInBackground方法,doInBackground方法執行完成後返回結果作爲postResult的參數,接

下來我們看一看postResult方法。

步驟五、doInBackground方法返回的結果作爲參數傳進來後,在postResult方法中利用hanlder發送了一個MESSAGE_POST_RESULT msg

我們在handler中可以看到,MESSAGE_POST_RESULT消息接收器中,收到消息後就執行了finish(result.mData[0])方法,接下來我們來看一

下finish方法,在這個方法中調用isCancelled()來判斷任務是否被取消,如果被取消則在onCancelled方法中返回結果,否則調用onPostExecute

方法。

至此AsyncTask的執行過程就已經分析完了,接下來我們就來看onProgressUpdate的執行過程,我們知道要onProgressUpdate執行就必須在

doInBackground方法中調用publishProgress方法才行,那我們就來看publishProgress方法的代碼,從他的代碼中我們可以看出,他利用

handler發送了一個MESSAGE_POST_PROGRESS的消息,那麼來看handler接收器,從handler接收器中可以看到,在這裏調用了

onProgressUpdate方法了。這就是onProgressUpdate方法的執行過程。從他的調用過程中我們可以看到,這個方法其實是在主線程中執行的

這也是爲什麼能夠在這個方法中進行UI更新的操作。

總結:創建AsyncTask對象,會創建一個線程池,調用excute方法啓動任務後,doInBackground會在線程池中執行,其他的方法都是在主線程

中被執行。所以所有關於UI的操作都不能在doInBackground中進行操作。

接下來的任務就是怎樣來調用需要自定義一些數據結構的方法了。下篇博文見吧。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章