Android後臺任務(HandlerThread、AsyncTask、IntentService)

❀卜卜ღ?Bruce發表於2019-03-12

執行緒只是最基本的應用,在複雜的場景下使用Thread程式碼可讀性會變的很多差而且也容易出錯。 android為了簡化開發者的工作量,提供了一些更容易使用的封裝。

HandlerThread

為了讓Handler在非主執行緒工作,可以使用HandlerThread。 如題使用如下:

    Handler handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        HandlerThread handlerThread = new HandlerThread("backThread",Process.THREAD_PRIORITY_BACKGROUND);
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
    }
複製程式碼

使用HandlerThread的Looper之後,Handler就是在HandlerThread所線上程中處理訊息了。 其實HandlerThread就是新建了執行緒,然後呼叫了Looper.prepare();Looper.loop();

AsyncTask

AsyncTask 現在使用的人已經不多了,它也是一個使用很簡單的後臺任務類,開發者不需要關注Thread和Handler就能在後臺執行緒完成輕量級和時間較短的任務,並且最後在UI執行緒更新。

/*第一個為入參型別
 *第二個是進度型別
 *第三個是結果型別
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");
     }
 }
複製程式碼

下面可以看方法在哪個執行緒呼叫 :

    @WorkerThread
    protected abstract Result doInBackground(Params... params);

    @MainThread
    protected void onPreExecute() {
    }
    @MainThread
    protected void onPostExecute(Result result) {
    }

    @MainThread
    protected void onProgressUpdate(Progress... values) {
    }

複製程式碼

其實AsyncTask有一個包含一個靜態的執行緒池,最小同時執行兩個執行緒,最多4個執行緒。

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

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

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    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;
    }
複製程式碼

其中還有一個handler用於更新UI執行緒。

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

    private Handler getHandler() {
        return mHandler;
    }
複製程式碼

由於都是靜態的,所以其實所有的AsyncTask都是公用這個執行緒池和Handler。 AsyncTask使用起來也很簡單,但是有一些限制,只能在UI執行緒例項化和呼叫。

new DownloadFilesTask().execute(url1,url2,url3);
複製程式碼

IntentService

IntentService是為了處理非同步任務而對Service的封裝。 其實原理也很簡單。

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

    @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 void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
複製程式碼

就是在Service的OnCreate裡建立了一個HandlerThread,然後把需要處理的Intent傳送到這個Handler在後臺執行緒中處理並且完畢後呼叫stopSelf關閉服務。

使用上和Service一樣,就是需要重寫onHandleIntent方法。

相關文章