Android中的IPC方式
在Android中實現跨進程通信的方式有很多,具體的方式主要有以下幾種:
1. 使用Bundle
2. 使用文件共享
3. 使用Messenger
4. 使用AIDL
5. 使用ContentProvider
6. 使用Socket
以下是各種IPC方式的優缺點和適用場景,圖片源自《Android開發藝術探索》P121。
爲什麼可以使用Bundle實現IPC
我們知道,Intent是Android程序中各組件之間進行交互的一種重要方式,它不僅可以指明當前組件想要執行的操作,還可以在不同的組件之間傳遞數據。
- 利用Intent傳遞數據主要分兩種,基本類型數據和對象。
- 但值得注意的是利用Intent來傳遞數據,它對要傳遞的數據類型是有要求的,我們傳輸的數據必須要能夠被序列化。
- 我們知道基本類型是能夠被序列化的,那麼對象呢?Android中主要有兩種方式來實現對象序列化:Serilable接口和Parcelable接口。而Bundle爲什麼可以藉助Intent來實現IPC呢?因爲在Android中,有許多實現了Parcelable接口的類,如Bundle、Intent、Bitmap,同時List和Map也可序列化,前提是它們裏面的每個元素才能序列化。這就解釋了爲什麼我們可以利用Bundle來實現IPC了,同時也解釋了爲什麼Intent本身也可以攜帶基本數據進行數據傳遞。下面用實際的例子來展示利用Intent作爲載體傳遞基本數據,以及利用Intetn使用Bundle作爲載體來實現進行間通信的具體實現。
使用Bundle和Intent傳遞數據
利用Intent本身作爲載體傳遞基本類型數據
- 實現思路:利用Intent中提供的一系統putExtra()方法的重載,把我們想要傳遞的數據暫存於Intent中,當要取數據的時候利用getXXXExtra()方法將數據從Intent中取出來。其中putExtra()方法接收兩個參數,第一個參數鍵,用於後面從Intent中取值,第二個參數纔是真正要傳遞的數據,getXXXExtra()方法根據要提取的數據的類型選擇不用的方法,例如傳遞是的字符串,則用getStringExtra()方法,若是布爾類型,則用getBooleanExtra()方法,依次類推,注:除了String類型的getStrignExtra()是隻傳入一個鍵值參數外,其他基本類型的方法都是需要輸入兩個參數的,第一個是鍵值,第二個是默認數據值(當按鍵值找不到對應的數據時,就回返回這個默認的值)。
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
String data1 = "Hello";
Double data2 = 98.0;
intent.putExtra("data1_key",data1);
intent.putExtra("data2_key",data2);
startActivity(intent);
- 說明:在FirstActivity中傳遞一個字符串“Hello”和一個雙精度常數98.0。
Intent在這裏的作用有兩個,其一是用於啓動從FirstActivity活動到SecondActivity活動 其二是作爲傳遞數據載體。
Intent intent = getIntent();
String data1 = intent.getStringExtra("data1_key");
Double data2 = intent.getDoubleExtra("data2_key",1);
- 說明:在SecondActivity中先通過getIntent();方法獲得啓動SecondActivity活動的Intent的實例,然後利用getXXXExtra()方法來提取數據。
2. Intent結合Bundle作爲載體進行數據傳遞
- 實現思路:把需要傳遞的數據都保存在Bundle對象中,然後將Bundle對象存放在Intent裏,提取數據時,先從Intent中取出Bundle,再從Bundle中逐一取出數據。
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
String data1 = "Hello";
Double data2 = 98.0;
Bundle bundle = new Bundle();
bundle.putString("data1_key",data1);
bundle.putDouble("data2_key",data2);
intent.putExtras(bundle);
- 說明:在FirstActivity中傳遞一個字符串“Hello”和一個雙精度常數98.0,利用putXXX(key
value)方法將數據在於一個Bundle對象中,然後把Bundle對象放在Intent中。
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
String data1 = bundle.getString("data1_key");
Double data2 = bundle.getDouble("data2_key")
- 說明:在SecondActivity中,先通過getIntent()方法獲取啓動SecondActivity的Intent實例,接着利用getExtras()方法從Intent中取出Bundle,然後再從Bundle對象利用getXXX(key)方法取出數據。
3. 使用Bundle解決活動被回收會失去臨時數據的問題
應用場景:應用中有一個活動A,用戶在活動A的基礎上啓動了活動B,活動A就會進入停止狀態,這時由於系統的內存不足,將活動A回收了,此時當用戶從活動B中按Back鍵返回活動A的時候,由於活動A已被回收,此時會重新創建一次(即此時活動A並不會執行onRestart()方法,而是執行onCreate()方法),那麼活動A中的臨時數據和狀態都會全沒了。
解決辦法:活動的onCreate()方法中有一個Bundle類型的參數,這個參數在一般情況下都是null的,但是如果在活動系統在回收之前有通過onSvaeInstanceState()方法的Bundle參數來保存數據的話,活動的onCreate()方法的Bundle參數就會帶有之前所保存的全部數據,我們只需要再通過相應的取值方法將數據取出就可以了。
1). 在活動A中重寫onSaveInstanceState()方法,利用該方法裏面攜帶的Bundle參數,來存入存放臨時的數據。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String temData = "Something you want to save";
outState.putString("data_key", temData);
}
說明:利用putString(key,value)方法將一個字符串在於Bundle參數的outState中。
2). 在活動A的onCreate()方法中取出數據。
protected void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState != null){
String temData = savedInstanceState.getString("data_key");
}
...
說明:利用getString(key)方法從Bundle參數的saveInstaceState中取出相應的數據。