Android進程模型java
在安裝Android應用程序的時候,Android會爲每一個程序分配一個Linux用戶ID,並設置相應的權限,這樣其它應用程序就不能訪問此應用程序所擁有的數據和資源了。linux
在 Linux 中,一個用戶ID 識別一個給定用戶;在 Android 上,一個用戶ID 識別一個應用程序。應用程序在安裝時被分配用戶 ID,應用程序在設備上的存續期間內,用戶ID 保持不變。android
默認狀況下,每一個apk運行在它本身的Linux進程中。當須要執行應用程序中的代碼時,Android會啓動一個jvm,即一個新的進程來執行,所以不一樣的apk運行在相互隔離的環境中。安全
下圖顯示了:兩個 Android 應用程序,各自在其本身的基本沙箱或進程上,他們是不一樣的Linux user ID。網絡
開發者也能夠給兩個應用程序分配相同的linux用戶id,這樣他們就能訪問對方所擁有的資源。架構
爲了保留系統資源,擁有相同用戶id的應用程序能夠運行在同一個進程中,共享同一個jvm。jvm
以下圖,顯示了兩個 Android 應用程序,運行在同一進程上。ide
不一樣的應用程序能夠運行在相同的進程中。要實現這個功能,首先必須使用相同的私鑰簽署這些應用程序,而後必須使用 manifest 文件給它們分配相同的 Linux 用戶 ID,這經過用相同的值/名定義 manifest 屬性 android:sharedUserId 來作到。工具
Android進程的知識補充oop
下圖是標準的Android 架構圖
其中咱們能夠看到在「Android本地庫 & Java運行環境層」中,Android 運行時中,
Dalvik是Android中的java虛擬機,可支持同時運行多個虛擬機實例;每一個Android應用程序都在本身的進程中運行,都擁有一個獨立的Dalvik虛擬機實例;
全部java類通過java編譯器編譯,而後經過SDK中的dx工具轉成.dex格式交由虛擬機執行。
Android系統進程
init進程(1號進程),父進程爲0號進程,執行根目錄底下的init可執行程序,是用戶空間進程
——-> /system/bin/sh
——-> /system/bin/mediaserver
——-> zygote
—————–> system_server
—————–>com.android.phone
—————–>android.process.acore(Home)
… …
kthreadd進程(2號進程),父進程爲0號進程,是內核進程,其餘內核進程都是直接或者間接以它爲父進程
Android的單線程模型
當一個程序第一次啓動時,Android會同時啓動一個對應的主線程(Main Thread),主線程主要負責處理與UI相關的事件,如:用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。因此主線程一般又被叫作UI線程。
在開發Android 應用時必須遵照單線程模型的原則: Android UI操做並非線程安全的而且這些操做必須在UI線程中執行。
若是在非UI線程中直接操做UI線程,會拋出android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views,這與普通的java程序不一樣。
因爲UI線程負責事件的監聽和繪圖,所以,必須保證UI線程可以隨時響應用戶的需求,UI線程裏的操做應該向中斷事件那樣短小,費時的操做(如網絡鏈接)須要另開線程,不然,若是UI線程超過5s沒有響應用戶請求,會彈出對話框提醒用戶終止應用程序。
若是在新開的線程中須要對UI進行設定,就可能違反單線程模型,所以android採用一種複雜的Message Queue機制保證線程間通訊
Message Queue:
Message Queue是一個消息隊列,用來存放經過Handler發佈的消息。Android在第一次啓動程序時會默認會爲UI thread建立一個關聯的消息隊列,能夠經過Looper.myQueue()獲得當前線程的消息隊列,用來管理程序的一些上層組件,activities,broadcast receivers 等等。你能夠在本身的子線程中建立Handler與UI thread通信。
經過Handler你能夠發佈或者處理一個消息或者是一個Runnable的實例。每一個Handler都會與惟一的一個線程以及該線程的消息隊列管理。
Looper扮演着一個Handler和消息隊列之間通信橋樑的角色。程序組件首先經過Handler把消息傳遞給Looper,Looper把消息放入隊列。Looper也把消息隊列裏的消息廣播給全部的Handler,Handler接受到消息後調用handleMessage進行處理。
實例以下:
public class MainActivity extends Activity implements OnClickListener { private EditText etTXT; private Button btnTXT; private TextView tvTXT; private MessageHandler messageHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etTXT = (EditText)findViewById(R.id.etTXT); btnTXT = (Button)findViewById(R.id.btnTXT); tvTXT = (TextView)findViewById(R.id.tvTXT); btnTXT.setOnClickListener(this); Looper looper = Looper.myLooper(); // 獲得當前線程的Looper實例 Looper looper2 = Looper.getMainLooper(); // 因爲當前線程是UI線程,因此也能夠經過Looper.getMainLooper()獲得 messageHandler = new MessageHandler(looper); // 此處甚至能夠不須要設置Looper,由於 Handler默認就使用當前線程的Looper } @Override public void onClick(View v) { new Thread(){ @Override public void run(){ Message msg = Message.obtain(); msg.obj = etTXT.getText().toString(); messageHandler.sendMessage(msg); } }.start(); } // 構造Hanlder class MessageHandler extends Handler{ public MessageHandler(Looper looper){ super(looper); } @Override public void handleMessage(Message msg){ tvTXT.setText((String)msg.obj); } } }
對於這個實例,當這個activity執行完onCreate,onStart,onResume後,就監聽UI的各類事件(如Click點擊事件)和消息(如Handler Message)。
當點擊一個按鈕後啓動線程,線程執行結束後經過handler發送一個消息,因爲這個handler屬於UI線程,所以這個消息也發送給UI線程,而後UI線程又把這個消息給handler處理,而這個handler是UI線程創造的,它能夠訪問UI組件,所以就更新了頁面。
因爲經過handler須要本身管理線程類,若是業務稍微複雜,代碼看起來就比較混亂,所以android提供了AsyncTask類來解決此問題
AsyncTask
首先繼承一下此類,實現如下若干方法:
1) onPreExecute(),該方法將在執行實際的後臺操做前被UI thread調用。能夠在該方法中作一些準備工做,如在界面上顯示一個進度條。
2) doInBackground(Params...),將在onPreExecute 方法執行後立刻執行,該方法運行在後臺線程中。這裏將主要負責執行那些很耗時的後臺計算工做。
能夠調用publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。
3) onProgressUpdate(Progress...),在publishProgress方法被調用後,UI thread將調用這個方法從而在界面上展現任務的進展狀況,例如經過一個進度條進行展現。
4) onPostExecute(Result),在doInBackground 執行完成後,onPostExecute 方法將被UI thread調用,後臺的計算結果將經過該方法傳遞到UI thread.
使用時須要遵循如下規則:
1)Task的實例必須在UI thread中建立
2)execute方法必須在UI thread中調用
3)不要手動的調用這些方法,只調用execute便可
4)該task只能被執行一次,不然屢次調用時將會出現異常
示例以下:
public class MainActivity extends Activity implements OnClickListener { private EditText etTXT; private Button btnTXT; private TextView tvTXT; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etTXT = (EditText)findViewById(R.id.etTXT); btnTXT = (Button)findViewById(R.id.btnTXT); tvTXT = (TextView)findViewById(R.id.tvTXT); btnTXT.setOnClickListener(this); } @Override public void onClick(View v) { String txt = etTXT.getText().toString(); new MyTask().execute(txt); } // 構造AsyncTask class MyTask extends AsyncTask<String, Integer, String>{ @Override protected String doInBackground(String... params) { // 在後臺執行後返回結果 result return params[0].toString(); } @Override protected void onPostExecute(String result) { // 捕獲後臺返回的結果 result tvTXT.setText(result.toString()); // 顯示結果result } } }
運行結果: