Android 中的“子線程”解析

Android 中線程可分為主線程子線程兩類(lèi)辙纬,其中主線程也就是UI線程瓷马,它的主要這作用就是運(yùn)行四大組件、處理界面交互膝宁。子線程則主要是處理耗時(shí)任務(wù)鸦难,也是我們要重點(diǎn)分析的。

首先 Java 中的各種線程在 Android 里是通用的员淫,Android 特有的線程形態(tài)也是基于 Java 的實(shí)現(xiàn)的合蔽,所以有必要先簡(jiǎn)單的了解下 Java 中的線程,本文主要包括以下內(nèi)容:

  • Thread介返、Runnable
  • Callable拴事、Future
  • 線程池
  • IntentService、HandlerThread
  • AsyncTask

一圣蝎、Thread刃宵、Runnable

在 Java 中要?jiǎng)?chuàng)建子線程可以直接繼承Thread類(lèi),重寫(xiě)run()方法:

public class MyThread extends Thread {
        @Override
        public void run() {
            
        }
    }
// 啟動(dòng)線程
new MyThread().start();

或者實(shí)現(xiàn)Runnable接口徘公,然后用Thread執(zhí)行Runnable牲证,這種方式比較常用:

public class MyRunnable implements Runnable {
        @Override
        public void run() {

        }
    }
// 啟動(dòng)線程
new Thread(new MyRunnable()).start();

簡(jiǎn)單的總結(jié)下:

  • Runnable 可以實(shí)現(xiàn)多個(gè)線程共享資源,可以參考網(wǎng)上賣(mài)票的例子
  • Runnable 可以避免 Java 中的單繼承的限制
  • 無(wú)法直接得到任務(wù)的執(zhí)行結(jié)果

二关面、Callable坦袍、Future

CallableRunnable類(lèi)似,都可以用來(lái)處理具體的耗時(shí)任務(wù)邏輯的缭裆,但是但具體的差別在哪里呢键闺?看一個(gè)小例子:

定義 MyCallable 實(shí)現(xiàn)了 Callable接口,和之前Runnablerun()方法對(duì)比下澈驼,call()方法是有返回值的哦辛燥,泛型就是返回值的類(lèi)型:

public class MyCallable implements Callable<String> {
        @Override
        public String call() throws Exception {
            Log.e("call", "task start");
            Thread.sleep(2000);
            Log.e("call", "task finish");
            return "hello thread";
        }
    }

一般會(huì)通過(guò)線程池來(lái)執(zhí)行Callable(線程池相關(guān)內(nèi)容后邊會(huì)講到),執(zhí)行結(jié)果就是一個(gè)Future對(duì)象:

        // 創(chuàng)建一個(gè)線程池
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        // 執(zhí)行任務(wù)
        Future<String> result = cachedThreadPool.submit(new MyCallable());
        try {
            // 獲取執(zhí)行結(jié)果
            Log.e("result", result.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

可以看到,通過(guò)線程池執(zhí)行 MyCallable 對(duì)象返回了一個(gè) Future 對(duì)象挎塌,取出執(zhí)行結(jié)果徘六。

Future是一個(gè)接口,從其內(nèi)部的方法可以看出它提供了取消任務(wù)(有坑A穸肌4狻!)嘴高、判斷任務(wù)是否完成竿音、獲取任務(wù)結(jié)果的功能:

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

Future接口有一個(gè)FutureTask實(shí)現(xiàn)類(lèi),同時(shí)FutureTask也實(shí)現(xiàn)了Runnable接口拴驮,并提供了兩個(gè)構(gòu)造函數(shù):

public FutureTask(Callable<V> callable) {
}

public FutureTask(Runnable runnable, V result) {
}

FutureTask一個(gè)參數(shù)的構(gòu)造函數(shù)來(lái)改造下上邊的例子:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
cachedThreadPool.submit(futureTask);
try {
     Log.e("result", futureTask.get());
} catch (InterruptedException e) {
     e.printStackTrace();
} catch (ExecutionException e) {
     e.printStackTrace();
}

FutureTask內(nèi)部有一個(gè)done()方法春瞬,代表Callable中的任務(wù)已經(jīng)結(jié)束,可以用來(lái)獲取執(zhí)行結(jié)果:

FutureTask<String> futureTask = new FutureTask<String>(new MyCallable()){
            @Override
            protected void done() {
                super.done();
                try {
                    Log.e("result", get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        };

所以Future + Callable的組合可以更方便的獲取子線程任務(wù)的執(zhí)行結(jié)果套啤,更好的控制任務(wù)的執(zhí)行宽气,主要的用法先說(shuō)這么多了,其實(shí)AsyncTask內(nèi)部也是類(lèi)似的實(shí)現(xiàn)潜沦!

注意萄涯,Future并不能取消掉運(yùn)行中的任務(wù),這點(diǎn)在后邊的AsyncTask解析中有提到唆鸡。

三涝影、線程池

Java 中線程池的具體的實(shí)現(xiàn)類(lèi)是ThreadPoolExecutor,繼承了Executor接口喇闸,這些線程池在 Android 中也是通用的袄琳。使用線程池的好處:

  • 方便對(duì)線程進(jìn)行管理
  • 線程復(fù)用,避免大量創(chuàng)建燃乍、銷(xiāo)毀線程帶來(lái)的性能開(kāi)銷(xiāo)
  • 可控制線程的最大并發(fā)數(shù)唆樊,避免線程之間搶占資源造成阻塞

常用的構(gòu)造函數(shù)如下:

public ThreadPoolExecutor(
                // 線程池的核心線程數(shù),如果設(shè)置allowCoreThreadTimeOut屬性為true刻蟹,當(dāng)閑置時(shí)間大于keepAliveTime會(huì)被終止掉逗旁,否則會(huì)一直存活不受keepAliveTime影響
                int corePoolSize, 
                // 線程池能容納的最大線程數(shù),超過(guò)該數(shù)量的將會(huì)被阻塞
                int maximumPoolSize,
                // 線程閑置的超時(shí)時(shí)間
                long keepAliveTime,
                // 超時(shí)時(shí)間的單位
                TimeUnit unit,
                // 線程池的任務(wù)隊(duì)列舆瘪,保存通過(guò)execute()提交的Runnable片效,如果任務(wù)隊(duì)列已滿(mǎn),則后續(xù)任務(wù)不被執(zhí)行
                BlockingQueue<Runnable> workQueue,
                // 創(chuàng)建新的線程
                ThreadFactory threadFactory) {
    }

一個(gè)常規(guī)線程池可以按照如下方式來(lái)實(shí)現(xiàn):

public class ThreadPool {
    // CPU核心數(shù)
    private int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // 可同時(shí)下載的任務(wù)數(shù)(核心線程數(shù))
    private int CORE_POOL_SIZE = CPU_COUNT;
    // 線程池容納的最大線程數(shù)
    private int MAX_POOL_SIZE = 2 * CPU_COUNT + 1;
    // 超時(shí)時(shí)間
    private long KEEP_ALIVE = 10L;

    private ThreadPoolExecutor THREAD_POOL_EXECUTOR;

    private ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger();

        @Override
        public Thread newThread(@NonNull Runnable runnable) {
            return new Thread(runnable, "download_task#" + mCount.getAndIncrement());
        }
    };

    private ThreadPool() {
    }

    public static ThreadPool getInstance() {
        return SingletonHolder.instance;
    }

    private static class SingletonHolder {
        private static final ThreadPool instance = new ThreadPool();
    }

    private ThreadPoolExecutor getThreadPoolExecutor() {
        if (THREAD_POOL_EXECUTOR == null) {
            THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
                    CORE_POOL_SIZE,
                    MAX_POOL_SIZE,
                    KEEP_ALIVE,
                    TimeUnit.SECONDS,
                    new LinkedBlockingDeque<Runnable>(),
                    sThreadFactory);
        }
        return THREAD_POOL_EXECUTOR;
    }

    public void execute(Runnable command) {
        getThreadPoolExecutor().execute(command);
    }
}

執(zhí)行任務(wù):

ThreadPool.getInstance().execute(new Runnable() {
            @Override
            public void run() {
                // do something
            }
        });

基于ThreadPoolExecutor英古,系統(tǒng)擴(kuò)展了幾類(lèi)具有新特性的線程池:

// 創(chuàng)建一個(gè)線程數(shù)量固定的線程池淀衣,核心線程數(shù)就是線程池能容納的最大線程數(shù),同時(shí)線程將一直存活召调,除非線程池被關(guān)閉
// 如果任何線程在執(zhí)行期間因故障而終止膨桥,在關(guān)閉之前蛮浑,如果需要,新線程將取代它執(zhí)行后續(xù)任務(wù),
// 如果所有線程都處于活動(dòng)狀態(tài)只嚣,新來(lái)的任務(wù)需要等待沮稚,直到有空閑線程
ExecutorService fixedThreadPool = Executors.newFixedThreadPool();
// 該線程池只有非核心線程,數(shù)量為Integer.MAX_VALUE
// 按需創(chuàng)建線程册舞,沒(méi)有空閑線程時(shí)會(huì)創(chuàng)建新線程蕴掏,否則復(fù)用空閑線程,任何任務(wù)都會(huì)被立即執(zhí)行
// 超時(shí)時(shí)間為60秒调鲸,當(dāng)線程池長(zhǎng)時(shí)間閑置時(shí)線程都會(huì)被終止掉盛杰,幾乎不占用系統(tǒng)資源
// 任務(wù)隊(duì)列比較特殊是SynchronousQueue,而非一般的LinkedBlockingQueue
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 創(chuàng)建一個(gè)核心線程數(shù)固定的線程池藐石,可容納的最大線程數(shù)量為Integer.MAX_VALUE饶唤,非核心線程的超時(shí)時(shí)間為0
// 主要用于執(zhí)行定時(shí)任務(wù)和有固定周期的任務(wù)
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool();
// 該線程池中只有一個(gè)核心線程,所有任務(wù)都通過(guò)該線程執(zhí)行
// 任務(wù)之間不用考慮線程同步的問(wèn)題
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
// Android api level 24 新加的
// 會(huì)根據(jù)所需的并行層次來(lái)動(dòng)態(tài)創(chuàng)建和關(guān)閉線程贯钩,試圖減少任務(wù)隊(duì)列的大小,所以比較適于高負(fù)載的環(huán)境
// 也比較適用于當(dāng)執(zhí)行的任務(wù)會(huì)創(chuàng)建更多任務(wù)办素,如遞歸任務(wù)
ExecutorService workStealingPool =  Executors.newWorkStealingPool();

線程池可以通過(guò)execute()角雷、submit()方法開(kāi)始執(zhí)行任務(wù),主要差別從方法的聲明就可以看出性穿,由于submit()有返回值勺三,可以方便得到任務(wù)的執(zhí)行結(jié)果:

void execute(Runnable command)
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
<T> Future<T> submit(Runnable task, T result)

要關(guān)閉線程池可以使用如下方法:

void shutdown()
List<Runnable> shutdownNow()

四、IntentService需曾、HandlerThread

1吗坚、基本使用

IntentService 是 Android 中一種特殊的 Service,可用于執(zhí)行后臺(tái)耗時(shí)任務(wù)呆万,任務(wù)結(jié)束時(shí)會(huì)自動(dòng)停止商源,由于屬于系統(tǒng)的四大組件之一,相比一般線程具有較高的優(yōu)先級(jí)谋减,不容易被殺死牡彻。用法和普通 Service 基本一致,只需要在onHandleIntent()中處理耗時(shí)任務(wù)即可:

public class DomainService extends IntentService {
    public DomainService() {
        super("DomainService");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        // 處理耗時(shí)任務(wù)
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

至于 HandlerThread出爹,它是 IntentService 內(nèi)部實(shí)現(xiàn)的重要部分庄吼,細(xì)節(jié)內(nèi)容會(huì)在 IntentService 源碼中說(shuō)到。

2严就、源碼解析

IntentService 首次創(chuàng)建被啟動(dòng)的時(shí)候其生命周期方法onCreate()會(huì)先被調(diào)用总寻,所以我們從這個(gè)方法開(kāi)始分析:

@Override
public void onCreate() {
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

這里出現(xiàn)了 HandlerThread 和 ServiceHandler 兩個(gè)類(lèi),先搞明白它們的作用梢为,以便后續(xù)的分析渐行。

首先看 HandlerThread 的核心實(shí)現(xiàn):

public class HandlerThread extends Thread {

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

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

首先它繼承了 Thread 類(lèi)轰坊,可以當(dāng)做子線程來(lái)使用,并在 run()方法中創(chuàng)建了一個(gè)消息循環(huán)系統(tǒng)殊轴、開(kāi)啟消息循環(huán)衰倦。

ServiceHandler 是 IntentService 的內(nèi)部類(lèi),繼承了 Handler旁理,具體內(nèi)容后續(xù)分析:

    private final class ServiceHandler extends Handler {
    }

現(xiàn)在回過(guò)頭來(lái)看 onCreate()方法主要是一些初始化的操作樊零, 首先創(chuàng)建了一個(gè) thread 對(duì)象,并啟動(dòng)線程孽文,然后用其內(nèi)部的 Looper 對(duì)象 創(chuàng)建一個(gè) mServiceHandler 對(duì)象驻襟,將子線程的 Looper 和 ServiceHandler 建立了綁定關(guān)系,這樣就可以使用mServiceHandler將消息發(fā)送到子線程去處理了芋哭。

生命周期方法 onStartCommand()方法會(huì)在 IntentService 每次被啟動(dòng)時(shí)調(diào)用沉衣,一般會(huì)這里處理啟動(dòng) IntentService 傳遞 Intent 解析攜帶的數(shù)據(jù):

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

又調(diào)用了start()方法:

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

就是用mServiceHandler發(fā)送了一條包含startIdintent的消息,消息的發(fā)送還是在主線程進(jìn)行的减牺,接下來(lái)消息的接收豌习、處理就是在子線程進(jìn)行的:

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)接收到消息時(shí),通過(guò)onHandleIntent()方法在子線程處理 intent 對(duì)象拔疚,onHandleIntent()方法執(zhí)行結(jié)束后肥隆,通過(guò)stopSelf(msg.arg1)等待所有消息處理完畢后終止服務(wù)。

為什么消息的處理是在子線程呢稚失?這里涉及到 Handler 的內(nèi)部消息機(jī)制栋艳,簡(jiǎn)單的說(shuō),因?yàn)?code>ServiceHandler使用的Looper對(duì)象就是在HandlerThread這個(gè)子線程類(lèi)里創(chuàng)建的句各,并通過(guò)Looper.loop()開(kāi)啟消息循環(huán)吸占,不斷從消息隊(duì)列(單鏈表)中取出消息,并執(zhí)行凿宾,截取loop()的部分源碼:

for (;;) {
    Message msg = queue.next(); // might block
    if (msg == null) {
         // No message indicates that the message queue is quitting.
         return;
    }
    msg.target.dispatchMessage(msg);
}

dispatchMessage()方法間接會(huì)調(diào)用handleMessage()方法矾屯,所以最終onHandleIntent()就在子線程中劃線執(zhí)行了,即HandlerThreadrun()方法初厚。

這就是 IntentService 實(shí)現(xiàn)的核心问拘,通過(guò)HandlerThread + Hanlder把啟動(dòng) IntentService 的 Intent 從主線程切換到子線程,實(shí)現(xiàn)讓 Service 可以處理耗時(shí)任務(wù)的功能惧所!

五骤坐、AsyncTask

1、基本使用

AsyncTask 是 Android 中輕量級(jí)的異步任務(wù)抽象類(lèi)下愈,它的內(nèi)部主要由線程池以及 Handler 實(shí)現(xiàn)纽绍,在線程池中執(zhí)行耗時(shí)任務(wù)并把結(jié)果通過(guò) Handler 機(jī)制中轉(zhuǎn)到主線程以實(shí)現(xiàn)UI操作。典型的用法如下:

    /**
     * 三個(gè)泛型參數(shù)Params势似、 Progress拌夏、 Result分別表示耗時(shí)任務(wù)輸入?yún)?shù)類(lèi)型僧著、進(jìn)度類(lèi)型、返回的結(jié)果類(lèi)型
     */
    public class DownloadAsyncTask extends AsyncTask<String, Integer, String> {
        /**
         * 在主線程執(zhí)行障簿,可在耗時(shí)任務(wù)開(kāi)始前做一些準(zhǔn)備工作
         */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            Log.e("onPreExecute", "download prepare");
        }

        /**
         * 在線程池中執(zhí)行耗時(shí)任務(wù)
         *
         * @param urls 輸入?yún)?shù)
         * @return 耗時(shí)任務(wù)的結(jié)果
         */
        @Override
        protected String doInBackground(String... urls) {
            String url = "";
            for (String temp : urls) {
                // 執(zhí)行耗時(shí)任務(wù)
                try {
                    for (int i = 0; i <= 100; i += 10) {
                        // publishProgress()用來(lái)更新任務(wù)進(jìn)度盹愚,會(huì)調(diào)用onProgressUpdate()方法
                        publishProgress(i);
                        Thread.sleep(20);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                url = temp;
            }

            return url;
        }

        /**
         * 在主線程執(zhí)行,進(jìn)度更新時(shí)會(huì)被調(diào)用
         *
         * @param values values[0]代表進(jìn)度
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            Log.e("onProgressUpdate", values[0] + "%");
        }

        /**
         * 在主線程執(zhí)行站故,耗時(shí)任務(wù)執(zhí)行結(jié)束
         *
         * @param url doInBackground()的返回值
         */
        @Override
        protected void onPostExecute(String url) {
            super.onPostExecute(url);
            Log.e("onPostExecute", url + " download finish");
        }
    }

從 Android3.0 開(kāi)始皆怕,AsyncTask 默認(rèn)是串行執(zhí)行的:

new DownloadAsyncTask().execute("url-1");
new DownloadAsyncTask().execute("url-2");

如果需要并行執(zhí)行可以這么做:

new DownloadAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "url-1");
new DownloadAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "url-2");
2、源碼解析

AsyncTask 的源碼不多西篓,還是比較容易理解的愈腾。根據(jù)上邊的用法,可以從execute()方法開(kāi)始我們的分析:

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

看到@MainThread注解了嗎岂津?所以execute()方法需要在主線程執(zhí)行哦虱黄!

進(jìn)而又調(diào)用了executeOnExecutor()

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

可以看到,當(dāng)任務(wù)正在執(zhí)行或者已經(jīng)完成吮成,如果又被執(zhí)行會(huì)拋出異常橱乱!回調(diào)方法onPreExecute()最先被執(zhí)行了。

傳入的sDefaultExecutor參數(shù)粱甫,是一個(gè)自定義的串行線程池對(duì)象仅醇,所有任務(wù)在該線程池中排隊(duì)執(zhí)行:

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

可以看到SerialExecutor線程池僅用于任務(wù)的排隊(duì),THREAD_POOL_EXECUTOR線程池才是用于執(zhí)行真正的任務(wù)魔种,就是我們線程池部分講到的ThreadPoolExecutor

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

再回到executeOnExecutor()方法中,那么exec.execute(mFuture)就是觸發(fā)線程池開(kāi)始執(zhí)行任務(wù)的操作了粉洼。

executeOnExecutor()方法中的mWorker是什么节预?mFuture是什么?答案在 AsyncTask 的構(gòu)造函數(shù)中:

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

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

原來(lái)mWorker是一個(gè)Callable對(duì)象属韧,mFuture是一個(gè)FutureTask對(duì)象安拟,繼承了Runnable接口。所以mWorkercall()方法會(huì)在mFuturerun()方法中執(zhí)行宵喂,所以mWorkercall()方法在線程池得到執(zhí)行糠赦!

同時(shí)doInBackground()方法就在call()中方法,所以我們自定義的耗時(shí)任務(wù)邏輯得到執(zhí)行锅棕,不就是我們第二部分講的那一套嗎拙泽!

doInBackground()的返回值會(huì)傳遞給postResult()方法:

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

就是通過(guò) Handler 將最終的耗時(shí)任務(wù)結(jié)果從子線程發(fā)送到主線程,具體的過(guò)程是這樣的裸燎,getHandler()得到的就是 AsyncTask 構(gòu)造函數(shù)中初始化的mHandler顾瞻,mHander又是通過(guò)getMainHandler()賦值的:

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

可以在看到sHandler是一個(gè)InternalHandler類(lèi)對(duì)象:

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

所以getHandler()就是在得到在主線程創(chuàng)建的InternalHandler對(duì)象,所以
就可以完成耗時(shí)任務(wù)結(jié)果從子線程到主線程的切換德绿,進(jìn)而可以進(jìn)行相關(guān)UI操作了荷荤。
當(dāng)消息是MESSAGE_POST_RESULT時(shí)退渗,代表任務(wù)執(zhí)行完成,finish()方法被調(diào)用:

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

如果任務(wù)沒(méi)有被取消的話(huà)執(zhí)行onPostExecute()蕴纳,否則執(zhí)行onCancelled()会油。

如果消息是MESSAGE_POST_PROGRESSonProgressUpdate()方法被執(zhí)行古毛,根據(jù)之前的用法可以onProgressUpdate()的執(zhí)行需要我們手動(dòng)調(diào)用publishProgress()方法翻翩,就是通過(guò) Handler 來(lái)發(fā)送進(jìn)度數(shù)據(jù):

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

進(jìn)行中的任務(wù)如何取消呢?AsyncTask 提供了一個(gè)cancel(boolean mayInterruptIfRunning)喇潘,參數(shù)代表是否中斷正在執(zhí)行的線程任務(wù)体斩,但是呢并不靠譜,cancel()的方法注釋中有這么一段:

Calling this method will result in {@link #onCancelled(Object)} being
invoked on the UI thread after {@link #doInBackground(Object[])}
returns. Calling this method guarantees that {@link #onPostExecute(Object)}
is never invoked. After invoking this method, you should check the
value returned by {@link #isCancelled()} periodically from
{@link #doInBackground(Object[])} to finish the task as early as
possible.

大致意思就是調(diào)用cancel()方法后颖低,onCancelled(Object)回調(diào)方法會(huì)在doInBackground()之后被執(zhí)行而onPostExecute()將不會(huì)被執(zhí)行絮吵,同時(shí)你應(yīng)該doInBackground()回調(diào)方法中通過(guò)isCancelled()來(lái)檢查任務(wù)是否已取消,進(jìn)而去終止任務(wù)的執(zhí)行忱屑!

所以只能自己動(dòng)手了:

  @Override
  protected String doInBackground(String... urls) {
      .........
      if (isCancelled()){
           // 手動(dòng)拋出異常蹬敲,并自己捕獲或者直接return
      }
      .........        
  }

AsyncTask 整體的實(shí)現(xiàn)流程就這些了,源碼是最好的老師莺戒,自己跟著源碼走一遍有些問(wèn)題可能就豁然開(kāi)朗了伴嗡!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末虱咧,一起剝皮案震驚了整個(gè)濱河市耿芹,隨后出現(xiàn)的幾起案子靶庙,更是在濱河造成了極大的恐慌悯搔,老刑警劉巖择懂,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炕舵,死亡現(xiàn)場(chǎng)離奇詭異幽污,居然都是意外死亡躺彬,警方通過(guò)查閱死者的電腦和手機(jī)伸辟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)麻惶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人信夫,你說(shuō)我怎么就攤上這事窃蹋。” “怎么了静稻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵警没,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我振湾,道長(zhǎng)惠奸,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任恰梢,我火速辦了婚禮佛南,結(jié)果婚禮上梗掰,老公的妹妹穿的比我還像新娘。我一直安慰自己嗅回,他們只是感情好及穗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著绵载,像睡著了一般埂陆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上娃豹,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天焚虱,我揣著相機(jī)與錄音,去河邊找鬼懂版。 笑死鹃栽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的躯畴。 我是一名探鬼主播民鼓,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蓬抄!你這毒婦竟也來(lái)了丰嘉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嚷缭,失蹤者是張志新(化名)和其女友劉穎饮亏,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體阅爽,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡路幸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了优床。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡誓焦,死狀恐怖胆敞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杂伟,我是刑警寧澤移层,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站赫粥,受9級(jí)特大地震影響观话,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜越平,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一频蛔、第九天 我趴在偏房一處隱蔽的房頂上張望灵迫。 院中可真熱鬧,春花似錦晦溪、人聲如沸瀑粥。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)狞换。三九已至,卻和暖如春舟肉,著一層夾襖步出監(jiān)牢的瞬間修噪,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工路媚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留黄琼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓磷籍,卻偏偏與公主長(zhǎng)得像适荣,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子院领,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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

  • Android中的線程 線程弛矛,在Android中是非常重要的,主線程處理UI界面比然,子線程處理耗時(shí)操作丈氓。如果在主線程...
    shenhuniurou閱讀 756評(píng)論 0 3
  • 學(xué)習(xí)內(nèi)容 線程基本概念 線程的不同形式AsyncTaskHandlerThreadIntentService 線程...
    whd_Alive閱讀 629評(píng)論 0 1
  • Java 多線程 線程和進(jìn)程的區(qū)別 線程和進(jìn)程的本質(zhì):由CPU進(jìn)行調(diào)度的并發(fā)式執(zhí)行任務(wù),多個(gè)任務(wù)被快速輪換執(zhí)行强法,使...
    安安zoe閱讀 2,200評(píng)論 1 18
  • 從用途上來(lái)說(shuō)万俗,線程分為主線程和子線程,主線程主要處理和界面相關(guān)的事情饮怯,子線程則往往用于執(zhí)行耗時(shí)操作闰歪。 除了Thre...
    小柏不是大白閱讀 629評(píng)論 0 3
  • 這一個(gè)多小時(shí)的課程,對(duì)我們平時(shí)的人脈管理和人際交往蓖墅,是一個(gè)很好的指引和梳理库倘。所以做一個(gè)詳細(xì)的學(xué)習(xí)筆記,可以循序漸進(jìn)...
    一刀2018閱讀 631評(píng)論 0 0