第九章 多程序(multiprocess)
阿新 • • 發佈:2019-01-24
一、多程序的基礎知識
◆ 為什麼使用多程序?
一個應用預設使用一個程序,這個程序(主程序)的名字就是應用的包名,程序是系統分配資源和排程的基本單位,每個程序都有自己獨立的資源和記憶體空間,其他程序不能任意訪問當前程序的記憶體和資源,系統給每個程序分配的記憶體會有限制。 如果一個程序佔用記憶體超過了這個記憶體限制,就會報OOM的問題。為了解決應用記憶體的問題,Android引入了多程序的概念,它允許在同一個應用內,廢了分擔主程序的壓力,將佔用記憶體的某些頁面單獨開一個程序,比如Flash、視訊播放頁面,頻繁繪製的頁面等。 使用多程序,需要在AndroidMainfest.xml的宣告中新增“android:process"屬性;process分私有程序和全域性程序兩種,私有程序的名稱前面有冒號,全部程序沒有。為了節省系統記憶體,在退出該Activity的時候可以將其殺掉(如果沒有人為殺掉該程序,在程式完全退出時該程序會被系統殺掉):<activity android:name=".aidl.AIDLActivity" android:label="@string/app_name" android:process=":other"> </activity>
protected void onDestroy() {
Process.killProcess(Process.myPid());
System.exit(0);
}
◆ 程序的等級
我們可以將一些元件執行在其他程序中,並且可以為任意的程序新增執行緒。元件執行在哪個程序中是在manifest檔案裡設定的,其中<Activity>,<Service>,<receiver>和<provider>都有一個process屬性來指定該元件執行在哪個程序之中。我們可以設定這個屬性,使得每個元件執行在它們自己的程序中,或是幾個元件共同享用一個程序,或是不共同享用。<application>元素也有一個process屬性,用來指定所有的元件的預設屬性。二、程序間的通訊 IPC(inter process communication)
1. messenger傳送訊息的方法
Messenger的使用包括兩個地方,一個是service端,一個是client端。 1. 先準備好一個Message,這個message可以通過Message.botain(Handler h,int what)獲得,可以新增Bundle資料以及replyTo; 2. 準備一個Messenger,這個Messenger可以通過new Messenger-Handler()或者msg.replyTo獲得; 3. Messenger.send(msg)傳送Message資料; 4. 在Handler的handleMessage()函式中獲得指定what的msg,進行處理。 注意:Messenger可以傳遞的資料型別由Message可以傳遞的資料型別決定,如果想傳遞一個自定義的類,那麼必須要保證這個類通過Parcelable或者Serializable序列化,然後放到Bundle物件中通過Message傳遞。 MessengerService類的實現:public class MessengerService extends Service {
private Handler messengerHandler = new Handler() {
//建立Handler用於處理MessengerActivity中傳遞的Message物件
public void handleMessage(Message message) {
switch (message.what) {
case 0:
//獲取內容並Toast
Toast.makeText(MessengerService.this, message.getData().getString("content"), Toast.LENGTH_SHORT).show();
//獲取MessengerActivity中replyMessenger物件,用來返回訊息
Messenger messenger = message.replyTo;
//建立返回訊息物件
Message replyMessage = Message.obtain(null, 0);
Bundle bundle = new Bundle();
bundle.putString("reply", "我已經收到訊息");
replyMessage.setData(bundle);
try {
//給MessengerActivity傳送訊息
messenger.send(replyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
};
private Messenger mMessenger = new Messenger(messengerHandler);
@Nullable
@Override
public IBinder onBind(Intent intent) {
//返回IBinder物件
return mMessenger.getBinder();
}
}
MessengerActivity類的實現:
public class MessengerActivity extends Activity {
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//通過服務返回的IBinder物件建立Messenger物件
Messenger messenger = new Messenger(service);
//建立訊息物件
Message message = new Message();
message.what = 0;
Bundle bundle = new Bundle();
bundle.putString("content","通過Messenger進行跨程序通訊");
message.setData(bundle);
//將接受訊息的replyMessenger傳遞給MessengerService
message.replyTo = replyMessenger;
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
/**
* 用於接收MessengerService傳遞來的資料Message物件
*/
private Messenger replyMessenger = new Messenger(new Handler(){
public void handlerMessage(Message message){
switch (message.what){
case 0:
//獲取資訊內容並Toast
Toast.makeText(MessengerActivity.this,message.getData().getString("reply"),Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
//繫結服務
bindService(new Intent(this,MessengerService.class),mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
}
2. AIDL(Android Interface definition language安卓介面定義語言)實現通訊
因為Messenger只適用於跨程序的單執行緒通訊,當處理多執行緒問題時,我們就需要使用AIDL進行通訊。1. 定義AIDL檔案 我們可以在main資料夾下建立一個aidle資料夾,在該資料夾下面點選NEW選擇新建AIDL檔案,系統會自動生成一個名叫IMyAidInterface.aidl的檔案(如下)。儲存後Android編譯器會在gen目錄下自動生成IMyAidInterface.java檔案,確保這些AIDL使用的環境建立完成;
// IMyAidlInterface.aidl
package com.example.administrator.threadexercise;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
<span style="white-space:pre"> </span>//以上為系統自動生成程式碼,也可以自己增加方法
String getName(String nickName);
}
2. 定義服務類AIDLService
public class AIDLService extends Service {
/**
* 例項化Stub類,Stub是該介面的一個內部類,繼承自bundle
*/
IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() {
//實現IMyAidInterface.aidl中的方法,這樣就可以通過IMyAidlInterface介面實現對Service的控制
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public String getName(String nickName) throws RemoteException {
return nickName + "aidl_hahaha";
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
//返回IBinder物件
return mStub;
}
}
3. 定義AIDLActivity類
public class AIDLActivity extends Activity {
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//通過服務返回的IBinder建立IMyAidInterface物件
mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IMyAidlInterface mIMyAidlInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mIMyAidlInterface != null){
try {
//呼叫getName方法
String name = mIMyAidlInterface.getName("nice_know_maco");
Toast.makeText(AIDLActivity.this,name+"",Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
bindService(new Intent(this, AIDLService.class),mServiceConnection, Context.BIND_AUTO_CREATE);
}
}