【筆記】【從Android Guide溫習Android 一】進程和線程(Process And thread)

 

【筆記】【從Android Guide溫習Android 一】進程和線程(Process And thread)

前言

  • 最近半年多的時間都在寫iOS,Android不少東西都在忘卻中。腦容量不足哇。html

  • 雖然作了2年多的android開發,但基礎知識總感受不是很牢固。linux

基於以上兩點,打算從新整理一下Android知識。從Android Guide入手。android

對於讀者,很是感謝抽出時間來看個人筆記,如有什麼錯誤請指正。有什麼意見能夠私信我。web

雖然從官方的Android Guide開始。安全

但說實話。我以爲官方文檔並不適合新人(做爲新人,我更喜歡iOS的文檔,固然也有可能我有android經驗。思路會類比一下感受很簡單)。多線程

若須要明白個8 9分的東西須要你具有必定的Android項目開發經驗才行。app

一切從這裏開始

當咱們啓動應用的最開始,先建立了一個linux進程和一個主線程,根據應用須要在建立了其餘進程和線程。而後全部的操做化做指令,逐一交付給線程執行。ide

來自Android Guide - Processes and Threads
When an application component starts and the application does not have any other components running, the Android system starts a new Linux process for the application with a single thread of execution. By default, all components of the same application run in the same process and thread (called the "main" thread). If an application component starts and there already exists a process for that application (because another component from the application exists), then the component is started within that process and uses the same thread of execution. However, you can arrange for different components in your application to run in separate processes, and you can create additional threads for any process.
大體以下
  • 當啓動app是,若當前沒有該app的組建(components)運行,那麼會建立一個linux進程。函數

  • 默認全部的組建都運行在同一個進程和線程(主線程)。post

  • 若是這個組建啓動時,要啓動的進程已經存在,則執行這個組建在這個進程的主線程中。

  • 你能夠建立不一樣的進程和線程。

組建(components)是指: activity, service, receiver, provider

進程(Process)

能夠經過設置AndroidManifest.xml中的組建屬性"android:process"來肯定運行在其餘進程。

<service android:name=".demo.service.remind.TYRemindServiceImpl"
         android:process="remindservice" /> <!-- remindservice -->
<service android:name=".demo.service.remind.TYRemindServiceImpl"
         android:process=":remindservice" /> <!-- :的做用:使得該線程名爲包名:remindservice -->

生命週期

  • 進程等級

    如下是由高等級到低等級的順序列出全部的進程等級以及他們的斷定條件。

    • Foreground process -- 前臺進程

      • Activity: 已經調用onResume()以後

      • Service: 已經綁定, 或設置foreground, 或正在執行生命週期的回調函數(onCreate,onStart,onDestory).

        這裏官方文檔沒說起onStartCommand,可是在Service中卻有體提到.

      • BroadcastReceiver: 正在執行onReceive

    • Visible process -- 可見進程

      當一個進程沒有前臺進程,但又正顯示在屏幕上:

      • Activity: 當前Activity是前臺進程並執行onPause方法。

      • Service: 已與前臺Activity綁定.

    • Service process -- 服務進程

      正在運行的Service,在經過 startService() 方法啓動的Service(由Service可知,並不符合前兩個等級)。

    • Background process -- 後臺進程

      Activity: 已執行onStop()後.該進程等級的斷定下降爲後臺進程等級。

      後臺進程對於用戶來講是不可見的,終結進程也不會影響用戶體驗。

      被終結以後,若正確使用狀態恢復(詳見Activity),用戶想要經過"最近訪問"重啓的時將會和以前的同樣。

    • Empty process -- 空進程

      沒有任何活動組建時。該進程等級爲最低。

      存在的意義僅僅是加速再次啓動的時間。

      這類進程會常常被終結。

  • 如何斷定進程的等級

    該進程的等級斷定受下面兩點影響

    • 由所包含的組建的最高等級而定。例如:

      一個進程中:Activity爲前臺進程等級,而且也運行了一個Service,該Service符合服務進程等級。那該進程的等級爲前臺進程等級。

    • 依賴進程而定。例如:

      ContentProvider正在爲另外一進程服務,或Service與另外一進程綁定,那前者的等級老是比後者高。

  • 進程終結時機及策略

    • 當系統內存緊張時,系統選擇終結進程的順序是根據等級由低到高執行。

    • 空進程會常常被回收,Service process以上等級的系統會盡可能保證存活

耗時工做的選擇

  • 因爲服務進程等級(Service process)要高於後臺進程(Background process)等級。

    因此當Activity進入後臺時,選擇Service處理耗時操做要比使用工做線程要好(如AsyncTask)。

    此時至少爲Service的進程等級。並且不用考慮Activity是否被銷燬。

  • 當BoardCastReceiver執行onReceive的時候,如有耗時操做。則應開啓Service而不是選擇建立其餘線程(如AsyncTask)。

線程(Thread)

主線程(Main Thread or UI Thread)

  • 啓動應用時,會建立及啓動主線程(Main Thread),或稱UI線程(UI Thread).

  • 主線程用於分發用戶事件(Touch event, drawing event)等。

  • 全部的組建都運行在主線程中。

  • Andoid UI toolkit(屬於android.widget 和 android.view包下的全部類) 均非線程安全。必須在主線程中使用。

  • 主線程中不要耗時操做,會阻塞用戶行爲的響應(點擊,刷新頁面),從而致使ANR的出現

工做線程(Worker Thread or Background Thread)

工做線程這個名字一開始讓我很困擾。覺得是什麼特殊的線程。其實沒什麼,只是相對於主線程的一種說法。

  • 耗時操做要在這裏進行。

  • 若須要刷新UI控件等涉及影響主線程的地方。能夠經過一下策略解決

    • View.post(Runnable) 和 View.postDelayed(Runnable, long) //僅針對View

    • Activity.runOnUiThread(Runnable) //隨時使用

    • Handler //因爲Handler依賴於建立時的線程,因此若主線程刷新。須要在主線程建立Handler,並在工做線程中發消息。

    • AsyncTask // 這個很少說。詳見官方文檔。

    • IntentService // 見其餘文檔。

下面是例子,均完成相同的操做,工做線程下載圖片,通知主線程顯示圖片。來自官方文檔

// 錯誤例子
new Thread(new Runnable() {
    public void run() {
        Bitmap b = loadImageFromNetwork("http://example.com/image.png");

        mImageView.setImageBitmap(b); // 這是錯誤的,違反"綜述"中的第4條
       }
}).start();

// 使用Activity
Activity activity = this;// 假設獲取Activity實例

new Thread(new Runnable() {
    public void run() {
        Bitmap b = loadImageFromNetwork("http://example.com/image.png");

        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mImageView.setImageBitmap(b); // 這是錯誤的,違反"綜述"中的第4條
            }
        });
    }
}).start();   

// 使用Post
public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
            mImageView.post(new Runnable() {
                public void run() {
                    mImageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

// 使用AsyncTask

public void onClick(View v) {
    new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    /** The system calls this to perform work in a worker thread and
      * delivers it the parameters given to AsyncTask.execute() */
    protected Bitmap doInBackground(String... urls) {
        return loadImageFromNetwork(urls[0]);
    }

    /** The system calls this to perform work in the UI thread and delivers
      * the result from doInBackground() */
    protected void onPostExecute(Bitmap result) {
        mImageView.setImageBitmap(result);
    }
}

// 使用Handler
// 在主線程建立Handler實例
private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        mImageView.setImageBitmap(msg.obj);
    }
};

new Thread(new Runnable() {
    public void run() {
        final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
        Message msg = handler.obtainMessage(0, bitmap);
        handler.sendMessage(msg);
    }
}).start();

線程安全

總的來講,當你使用多線程或多進程時,數據通信是比較繁瑣且易出錯的工做。

但你可使用Android的一些本地化特性,能夠幫你省去不少工做,好比官網舉兩點的例子。

  • Service的onBind()方法,此方法執行在主線程,而返回的對象將在線程池中被調用。

  • ContentProvider和ContentResolver一樣隱藏瞭如何管理進程間通信(IPC),入口看上去僅僅是insert(),delete()等操做。但你能夠在任意線程裏使用。

IPC(進程間通信)

官網僅說起了Service 經過綁定進行通信。使用Messenger.這部分之後在作介紹。

總結

  • 瞭解進程的生命週期很重要,好比重要的耗時工做放在Service中要比AsyncTask要安全。

  • 對於耗時操做,Android提供了多重特性能夠應對。並且使用簡單。

  • 涉及多線程,多進程的通信,利用特性(Handler,IBinder) 能夠簡單安全的解決。

  • 數據存儲。使用ContentProvider要優於存文件,不用考慮線程安全。

相關文章
相關標籤/搜索