2012年6月2日 星期六

[AndroidProcess] Background works

Main thread 負責處理 UI event,所以也稱為 UI thread,Activity、Service、Receiver、Provider,都是由 main thread 負責執行。因此不能在此 thread 中執行耗時的動作,android 會發出 ANR,這時候就得在 background thread 中執行,讓 main thread 同時仍能回應或執行 UI event,以避免 ANR 狀況。

sendBroadcast() 與 startService() 都一樣會被丟到 main message queue 裡,等待 main thread 的執行,只有呼叫 local content provider 不會進到 main message queue 裡,而是由 main thread 直接執行。但如果是 remote content provider 則是由 thread pool 中取得 thread 來執行,外部 client 呼叫 service 也是如此。

每個 Thread 中都有 Looper 和 Message Queue,Message Queue 中儲存著要被處理的 events (UI event and System event),Looper 負責 Thread 和 Message Queue 間的連繫。

另外,因為是 main thread 負責更新 UI,所以若是試圖在 worker thread 中更新 UI,是會得到 exception 的,必須把更新 UI 的動作再丟給 main thread 處理。


可選擇以下方式:

* Simple Worker Thread and runOnUiThread()/View.post()
View.post()
Each View object has a message queue which is processed sequentially on the UI thread. post() allows us to add a new message to the message queue.
new Thread(new Runnable() {
    @Override
    public void run() {
        // TODO works here.
        
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // UI event
            }
        });

        // or
        final TextView textView =
            (TextView) findViewById( R.id.textview );
        textView.post(new Runnable() {
            @Override
            public void run() {
                // UI event
                textView.setText( "Hello World" );
            }
        });
    }
}).start();

* new Thread + Handler
Handler: 負責處理 thread 的訊息(message)。
private Handler handler = new Handler() {
    @Override
    public void handleMessage(android.os.Message msg) {
        // UI event
        progressDialog.dismiss();
    };
}

new Thread() {new Runnable() {
    @Override
    public void run() {
        // TODO works here.

        // 把 message 送給 handler 處理。
        handler.sendEmptyMessage(0);

        // or 將 Runnable post 到 handler。
        handler.post(new Runnable() {
            @Override
            public void run() {
                textView.setText( "Hello World" );
            }
        });
    }
}.start();

* AsyncTask
  • 如果只會 Override doInBackground 則可考慮使用 Thread 即可。
  • AsyncTask 會 hold Activity context 直到工作結束,所以可能會有 context leak 問題。
new AsyncTask() {
    // onPreExecute(), onProgressUpdate()

    @Override
    protected Void doInBackground(Void... params) {
        // TODO works here.
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        // UI event
    };
}.execute();


** AsyncTask and Handler
  • AsyncTask 內部實做機制為較新且較強的 java.util.concurrent,但較佔資源,而 Handler Thread 則為基本的 Java Thread。
  • 由於 Handler Thread 依靠 Message Queue 與 Main Thread 互動,相對於 AsyncTask,Handler Thread 比較可能發生塞車情況。
  • 但 Handler Thread 在即時互動上優於 AsyncTask,因為 Main Thread 可以隨時傳送 Message 給 Handler Thread,而 AsyncTask 不行,只能依照事先定義 Callback 進行。
  • 基於輕量環境資源的有限,當執行單一的工作時建議使用 AsyncTask,如下載一個大檔案,但是當執行大量重複性的工作時,建議使用 Handler Thread,如下載多個小圖。

* Loader
  • Introduced in Android 3.0 and also included in the Support Library.
  • Used to asynchronously load data in an activity or fragment.
  • Quite effectively to perform these tasks:
    • Loading content either from a SQLite database or file storage, or from a network resource as a background task.
  • There are essentially three components that we need:
  • How to use:
    • Obtain LoaderManager instance from Activity/Fragment/FragmentActivity.
    • Implement LoaderManager.LoaderCallbacks.
      • Will create a loader.
      • Get called when the loader either finishes, or is reset.
      • These will all be executed on the UI thread, and we will typically implement them within our Activity / FragmentActivity.
      • 也就是在 Loader 中處理 UI event。(?)

* Service
  • Services is a means of performing some task which is not attached to a specific Activity.
  • Run in the main thread of their hosting process. (並不會在另一個 thread 中執行,所以不適做耗費 CPU 的工作 會有 ANR 的可能,或者是必須 new a thread。)
  • There are two types of Service:
    • A background Service
      • The default type of Service and can be killed by the OS (or Task Killer apps, more of them later) to free up system resources.
    • A foreground service
      • Not be killed by the OS, but requires an ongoing Notification to be displayed in the Notification bar while it is running so that the user is aware that the foreground Service is active and will not be killed automatically by the OS.
      • ex: music player.

* IntentService extends Service
  • Service + Handler + HandlerThread。
  • Will receive a single Intent and then shut down automatically once we have processed it.
  • 和 Service 不同,此 api 會執行在自己的 worker thread,陸續執行交給它的 request,但只會有一個 worker thread 同時也只會執行一個 request,當執行完後會自行停止。
  • 實做其 onHandleIntent(Intent intent),在這裡處理 request。
  • 是設計用來可以在一個 Service 中服務多項工作,因此在 onHandleIntent(),不可以呼叫 stopSelf(),全部工作結束,它會自行停止。
  • start service -> send message to handler that has non-UI thread looper -> handlerMessage() -> onHandleIntent()
    • Looper 就是訊息迴圈 (message loop),這是 Android UI 在處理各式訊息時,最重要的元件之一。
  • One word of warning:
    • Performing long tasks in an IntentService does have the inherent risk that it will stop if the device goes to sleep. You can prevent this from happening by holding a WakeLock while onHandleIntent() is executing. Just make sure you release it before onHandleIntent() returns. Alternatively use Mark Murphy’s WakefulIntentServicepattern.

* Pending
  • StrictMode
    • API level 9。
    • 可用於發現潛在問題,ex: 你該使用 background thread 的動作。
  • Loader
    • API level 11。


* Reference
- Background Tasks – Part 1 (Introduction)
- Background Tasks – Part 2 (Worker thread, Handler)
- Background Tasks – Part 3 (AsyncTask)
- Background Tasks – Part 4 (Loader)
- Background Tasks – Part 5 (Service)
- Background Tasks – Part 6 (IntentService)
- Android之Service与IntentService的比较 - HiPhoneZhu的专栏 - 博客频道 - CSDN.NET **
- 深入研究 IntentService 原始碼 ***
- IntentService的功用
- Android Handler 筆記 **
- Java Artisan: Android AsyncTask 與 Handler Thread 的差異 **
- Java Artisan: 在 Android 裡使用 Local Service

沒有留言:

張貼留言