Android中的線程形態(tài)

一玩焰、AsyncTask

AsyncTask是一種輕量級(jí)的異步任務(wù)類逆粹,它可以在線程池中執(zhí)行后臺(tái)任務(wù)募疮,然后把執(zhí)行的進(jìn)度和最終結(jié)果傳遞給主線程并在主線程中更新UI。從實(shí)現(xiàn)上說僻弹,AsyncTask封裝了Thread和Handler阿浓,通過AsyncTask可以更加方便的執(zhí)行后臺(tái)任務(wù)以及在主線程中訪問UI,但是AsyncTask并不適合進(jìn)行特別耗時(shí)的后臺(tái)任務(wù)蹋绽,耗時(shí)任務(wù)建議使用線程池芭毙。

四個(gè)核心方法

1、onPreExecute()卸耘,在主線程中執(zhí)行退敦,在異步任務(wù)執(zhí)行之前,此方法會(huì)被調(diào)用蚣抗,一般可以用于做一些準(zhǔn)備工作侈百。
2、doInBackground(Params ... params)翰铡,在線程池中執(zhí)行钝域,此方法用于執(zhí)行異步任務(wù),params參數(shù)表示異步任務(wù)的輸入?yún)?shù)锭魔。在此方法中可以通過publishProgress()方法更新任務(wù)進(jìn)度例证,publishProgress方法會(huì)調(diào)用onProgressUpdate方法。該方法需要返回計(jì)算結(jié)果給onPostExecute迷捧。
3织咧、onProgressUpdate(Progress ...values),在主線程中執(zhí)行漠秋,當(dāng)后臺(tái)任務(wù)的執(zhí)行進(jìn)度發(fā)生改變時(shí)此方法被調(diào)用烦感。
4、onPostExecute(Result result)膛堤,在主線程中執(zhí)行,在異步任務(wù)執(zhí)行之后晌该,此方法會(huì)被調(diào)用肥荔,其中result參數(shù)是后臺(tái)任務(wù)的返回值绿渣,即doInBackground的返回值。
5燕耿、onCancelled()中符,當(dāng)異步任務(wù)被取消時(shí),該方法被調(diào)用誉帅,此時(shí)onPostExecute則不會(huì)被調(diào)用淀散。

使用限制

1、之前的版本AsyncTask的對(duì)象必須在主線程中創(chuàng)建蚜锨,但最新版本下AsyncTask可以在子線程中創(chuàng)建档插。
2、execute方法必須在UI線程調(diào)用亚再。
3郭膛、不要再程序中直接調(diào)用onPreExecute()、onPostExecute氛悬、doInBackground和onProgressUpdate方法则剃。
4、一個(gè)AsyncTask對(duì)象只能執(zhí)行一次如捅,即只能調(diào)用一次execute方法棍现,否則會(huì)報(bào)運(yùn)行時(shí)異常。
5镜遣、Android3.0以及后續(xù)的版本中己肮,可以通過AsyncTask的executeOnExecutor方法來并行執(zhí)行任務(wù)。

工作原理
    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

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

        mStatus = Status.RUNNING;

        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

sDefaultExecutor實(shí)際上是一個(gè)串行的線程池烈涮,一個(gè)進(jìn)程中所有的AsyncTask全部在這個(gè)串行的線程池中排隊(duì)執(zhí)行朴肺。在executeOnExecutor方法中,AsyncTask的onPreExecute方法最先執(zhí)行坚洽,然后線程池開始執(zhí)行戈稿。

    /**
     * An {@link Executor} that executes tasks one at a time in serial
     * order.  This serialization is global to a particular process.
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

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

AsyncTask的排隊(duì)執(zhí)行過程:首先系統(tǒng)會(huì)把AsyncTask的Params參數(shù)封裝為FutureTask對(duì)象,F(xiàn)utureTask是一個(gè)并發(fā)類讶舰,在這里它充當(dāng)了Runnable的作用鞍盗。接著FutureTask交給SerialExecutor.execute方法處理。在execute方法中跳昼,futureTask首先被插入到任務(wù)隊(duì)列mTask中般甲,如果這個(gè)時(shí)候沒有正在活動(dòng)的任務(wù),則會(huì)調(diào)用scheduleNext方法執(zhí)行下一個(gè)AsyncTask任務(wù)鹅颊。當(dāng)一個(gè)AsyncTask任務(wù)執(zhí)行完后敷存,AsyncTask會(huì)繼續(xù)執(zhí)行其他任務(wù)直到所有的任務(wù)都被執(zhí)行為止。默認(rèn)情況下,AsyncTask是串行執(zhí)行的锚烦。

AsyncTask中有兩個(gè)線程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一個(gè)Handler(InternalHandler)觅闽,其中線程池SerialExecutor用于任務(wù)的排隊(duì),而線程池THREAD_POOL_EXECUTOR用于真正地執(zhí)行任務(wù)涮俄,InternalHandler用于將執(zhí)行環(huán)境從線程池切換到主線程蛉拙。

在SerialExecutor中調(diào)用了FutureTask.run()。而在FutureTask.run方法中最后又會(huì)調(diào)用mWorker.call()方法彻亲,因此mWorker.call最終在線程池中執(zhí)行孕锄。

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

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

    ##默認(rèn)情況下handler為InternalHandler
    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;
            }
        }
    }

在mWorker.call()中,首先將mTaskInvoked置為true苞尝,表示當(dāng)前任務(wù)已經(jīng)被調(diào)用過了畸肆,然后執(zhí)行AsyncTask.doInBackground方法,接著將其返回值傳遞給postResult方法野来。postResult方法會(huì)通過sHandler發(fā)送一個(gè)MESSAGE_POST_RESULT消息恼除。sHandler是一個(gè)靜態(tài)的Handler對(duì)象,為了能夠?qū)?zhí)行環(huán)境切換到主線程曼氛,sHandler必須在主線程中創(chuàng)建【其實(shí)按照現(xiàn)在的源碼來看豁辉,我的理解是不需要在主線程中聲明了,看下面代碼】舀患。

    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
    }

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

默認(rèn)情況下AsyncTask持有的mHandler即為sHandler徽级,而目前默認(rèn)給sHandler的looper為主線程Looper,因此就算在子線程中初始化了AsyncTask聊浅,sHandler的handleMessage方法依舊在主線程中執(zhí)行餐抢。
sHandler收到MESSAGE_POST_RESULT消息后調(diào)用AsyncTask.finish()方法。

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

如果AsyncTask被取消執(zhí)行了低匙,那么回調(diào)mCancelled方法旷痕,否則調(diào)用onPostExecute方法。

自身理解

google的工程師在AsyncTask的構(gòu)造方法中加入了Looper參數(shù)顽冶,意味AsyncTask目前擁有更自由的定制化程度欺抗,我們可以給它傳入子線程下的Looper,同時(shí)當(dāng)前AsyncTask的onPreExecute方法和onPostExecute方法均會(huì)在當(dāng)前線程下回調(diào)而不是默認(rèn)的主線程强重。

二绞呈、HandlerThread

HandlerThread繼承了Thread,它是一種可以使用Handler的Thread间景,在run方法中通過Looper.prepare()創(chuàng)建消息隊(duì)列佃声,并通過Looper.loop()來開啟消息循環(huán)。


public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    /**
     * @return a shared {@link Handler} associated with this thread
     * @hide
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    /**
     * Quits the handler thread's looper safely.
     * <p>
     * Causes the handler thread's looper to terminate as soon as all remaining messages
     * in the message queue that are already due to be delivered have been handled.
     * Pending delayed messages with due times in the future will not be delivered.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p>
     * If the thread has not been started or has finished (that is if
     * {@link #getLooper} returns null), then false is returned.
     * Otherwise the looper is asked to quit and true is returned.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }
}

它與普通Thread有顯著的不同之處倘要,普通Thread主要用于在run方法中執(zhí)行一個(gè)耗時(shí)任務(wù)圾亏,而HandlerThread在內(nèi)部創(chuàng)建了消息隊(duì)列,外部需要通過Handler的消息方式來通知HandlerThread執(zhí)行一個(gè)具體的任務(wù)。
當(dāng)明確不需要再使用HandlerThread時(shí)召嘶,可以通過它的quit或者quitSafely方法來終止線程的執(zhí)行父晶。

三、IntentService

IntentService繼承自Service且自身是一個(gè)抽象類弄跌,可用于執(zhí)行后臺(tái)耗時(shí)的任務(wù),當(dāng)任務(wù)執(zhí)行后它會(huì)自動(dòng)停止尝苇。IntentService的優(yōu)先級(jí)比單純的線程高很多铛只,適合執(zhí)行一些高優(yōu)先級(jí)的后臺(tái)任務(wù)。

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

當(dāng)IntentService第一次啟動(dòng)時(shí)糠溜,會(huì)創(chuàng)建一個(gè)HandlerThread淳玩,通過它的Looper創(chuàng)建mServiceHandler。

啟動(dòng)IntentService時(shí)非竿,onStartCommand方法被調(diào)用蜕着,而在onStartCommand中又調(diào)用了onStart方法。

onStart方法中包裝一個(gè)Message對(duì)象红柱,將intent交給mServiceHandler處理承匣,最終由onHandleIntent()方法處理傳入的Itnent對(duì)象,這里的intent與外界通過startService(Intent intent)方法中傳遞的Intent對(duì)象內(nèi)容一致锤悄,通過這個(gè)Intent即可解析出外界啟動(dòng)IntentService時(shí)傳遞的參數(shù)韧骗,通過參數(shù)區(qū)分具體的后臺(tái)任務(wù)。

當(dāng)onHandleIntent方法執(zhí)行結(jié)束后零聚,IntentService會(huì)通過stopSelf(int startId)方法嘗試停止服務(wù)袍暴,這里之所以采用stopSelf(int startId)而不是stopSelf()停止服務(wù),因?yàn)閟topSelft()會(huì)立刻停止服務(wù)隶症,而這個(gè)時(shí)候可能還有其他消息未處理政模,stopSelf(int startId)會(huì)等待所有的消息處理完畢后才終止服務(wù)。一般來說蚂会,stopSelf(int startId)在嘗試停止服務(wù)之前會(huì)判斷最近啟動(dòng)服務(wù)的次數(shù)是否和staratId相等淋样,如果相等就立刻停止服務(wù),不相等則不停止服務(wù)颂龙。

由于IntentService內(nèi)部通過消息的方式向HandlerThread請(qǐng)求執(zhí)行任務(wù)习蓬,Handler中的Looper是順序處理消息的,這就意味著IntentService也是順序執(zhí)行后臺(tái)任務(wù)措嵌,當(dāng)有多個(gè)后臺(tái)任務(wù)同時(shí)純?cè)跁r(shí)躲叼,這些后臺(tái)任務(wù)會(huì)按照外界發(fā)起的順序排隊(duì)執(zhí)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末企巢,一起剝皮案震驚了整個(gè)濱河市枫慷,隨后出現(xiàn)的幾起案子艰山,更是在濱河造成了極大的恐慌,老刑警劉巖招刹,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渔彰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡誉裆,警方通過查閱死者的電腦和手機(jī)顿颅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來足丢,“玉大人粱腻,你說我怎么就攤上這事≌兜” “怎么了绍些?”我有些...
    開封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耀鸦。 經(jīng)常有香客問我柬批,道長,這世上最難降的妖魔是什么袖订? 我笑而不...
    開封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任氮帐,我火速辦了婚禮,結(jié)果婚禮上著角,老公的妹妹穿的比我還像新娘揪漩。我一直安慰自己,他們只是感情好吏口,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開白布奄容。 她就那樣靜靜地躺著,像睡著了一般产徊。 火紅的嫁衣襯著肌膚如雪昂勒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天舟铜,我揣著相機(jī)與錄音戈盈,去河邊找鬼。 笑死谆刨,一個(gè)胖子當(dāng)著我的面吹牛塘娶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播痊夭,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼刁岸,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了她我?” 一聲冷哼從身側(cè)響起虹曙,我...
    開封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤迫横,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后酝碳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矾踱,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年疏哗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了呛讲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡返奉,死狀恐怖圣蝎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衡瓶,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布牲证,位于F島的核電站哮针,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏坦袍。R本人自食惡果不足惜十厢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捂齐。 院中可真熱鬧蛮放,春花似錦、人聲如沸奠宜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽压真。三九已至娩嚼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滴肿,已是汗流浹背岳悟。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泼差,地道東北人贵少。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像堆缘,于是被迫代替她去往敵國和親滔灶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容