正常情況下宿崭,一個apk啟動后只會運(yùn)行在一個進(jìn)程中,其進(jìn)程名為AndroidManifest.xml文件中指定的應(yīng)用包名汹桦,所有的基本組件都會在這個進(jìn)程中運(yùn)行朽合。但是如果需要將某些組件(如Service、Activity等)運(yùn)行在單獨(dú)的進(jìn)程中扔水,就需要用到Android:process屬性了痛侍。我們可以為android的基礎(chǔ)組件指定process屬性來指定它們運(yùn)行在指定進(jìn)程中。
有什么好處
一般來說魔市,Android應(yīng)用多進(jìn)程有三個好處主届。
1)我們知道Android系統(tǒng)對每個應(yīng)用進(jìn)程的內(nèi)存占用是有限制的,而且占用內(nèi)存越大的進(jìn)程待德,通常被系統(tǒng)殺死的可能性越大君丁。讓一個組件運(yùn)行在單獨(dú)的進(jìn)程中,可以減少主進(jìn)程所占用的內(nèi)存将宪,降低被系統(tǒng)殺死的概率.
2)如果子進(jìn)程因?yàn)槟撤N原因崩潰了绘闷,不會直接導(dǎo)致主程序的崩潰,可以降低我們程序的崩潰率较坛。
3)即使主進(jìn)程退出了印蔗,我們的子進(jìn)程仍然可以繼續(xù)工作,假設(shè)子進(jìn)程是推送服務(wù)丑勤,在主進(jìn)程退出的情況下华嘹,仍然能夠保證用戶可以收到推送消息。
怎么來實(shí)現(xiàn)
對process屬性的設(shè)置有兩種形式:
第一種形式如 android:process=":remote"法竞,以冒號開頭除呵,冒號后面的字符串原則上是可以隨意指定的。如果我們的包名為“com.example.processtest”爪喘,則實(shí)際的進(jìn)程名為“com.example.processtest:remote”颜曾。這種設(shè)置形式表示該進(jìn)程為當(dāng)前應(yīng)用的私有進(jìn)程,其他應(yīng)用的組件不可以和它跑在同一個進(jìn)程中秉剑。
第二種情況如 android:process="com.example.processtest.remote"泛豪,以小寫字母開頭,表示運(yùn)行在一個以這個名字命名的全局進(jìn)程中侦鹏,其他應(yīng)用通過設(shè)置相同的ShareUID可以和它跑在同一個進(jìn)程诡曙。
有哪些陷阱
其實(shí)開啟應(yīng)用內(nèi)多進(jìn)程會有一些陷阱,稍微不注意就會陷入其中略水。我們首先要明確的一點(diǎn)是進(jìn)程間的內(nèi)存空間是不可見的价卤。從而,開啟多進(jìn)程后渊涝,我們需要面臨這樣幾個問題:
1)Application的多次重建慎璧。
2)靜態(tài)成員的失效床嫌。
3)文件共享問題。
4)斷點(diǎn)調(diào)試問題胸私。
下面介紹一下AIDL
Android 兩個進(jìn)程之間無法直接通信厌处,只能通過系統(tǒng)底層間接通信
能實(shí)現(xiàn)這些功能的有AIDL、Binder岁疼、Messenger
AIDL是什么阔涉,就是Android Interface Description Language,Android接口定義語言
AIDL Binder Messenger之間的區(qū)別
分類 | IPC(進(jìn)程間通信) | 多線程 | 多個應(yīng)用程序 |
---|---|---|---|
AIDL | 支持IPC | 支持多線程 | 支持多個應(yīng)用程序 |
Binder | 只有IPC | 沒有多線程 | 支持多個應(yīng)用程序 |
Messenger | 只有IPC | 沒有多線程 | 不支持多個應(yīng)用程序 |
下面展示一下AIDL的使用方法捷绒,模擬遠(yuǎn)程計算功能
1.首先在main下創(chuàng)建一個AIDL文件夾
2.然后在aidl文件夾中創(chuàng)建aidl文件
創(chuàng)建完aidl文件后都需要build一下
3.創(chuàng)建一個service給其他進(jìn)程(app)使用
AIDL實(shí)質(zhì)就是使用service服務(wù)
注意:不要忘了在manifest定義,并且聲明他的進(jìn)程瑰排,如下
<service android:name=".service.IRemoteService"
android:process=":aidl">
<intent-filter>
<action android:name="action.aidl"/>
</intent-filter>
</service>
注意:這里添加了一個intent-filter,這是因?yàn)樵诓煌瑧?yīng)用程序之間使用aidl時暖侨,如果沒有intent-filter凶伙,會找不到service,此intent-filter就是為了能夠讓雙方建立聯(lián)系它碎。
public class IRemoteService extends Service {
/**
* 當(dāng)用戶綁定到該服務(wù)時會 執(zhí)行
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
//實(shí)現(xiàn)AIDL文件ITest的接口函荣,并生成iBinder供用戶綁定使用
private IBinder iBinder= new ITest.Stub() {
@Override
public int add(int num1, int num2) throws RemoteException {
Log.d("TAG", "已收到遠(yuǎn)程發(fā)送的數(shù)據(jù):num1=" + num1 + ";num2=" + num2);
return num1+num2;
}
};
}
4.新建一個ClientModuel以新建一個進(jìn)程模擬用戶,原來的app模擬服務(wù)器
同樣的方法新建一個AIDL文件夾扳肛,在這之下新建一個文件夾傻挂,文件夾名需要和服務(wù)端的一樣(非常重要),將同一個aidl拷貝到該目錄下挖息,build一下
5.實(shí)現(xiàn)遠(yuǎn)程計算功能
在client的MainActivity中綁定遠(yuǎn)程服務(wù)
public class MainActivity extends AppCompatActivity {
TextView tvSum;
EditText et1;
EditText et2;
Button btn;
ITest iTest;
private ServiceConnection connection=new ServiceConnection() {
//綁定上服務(wù)的時候
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//拿到遠(yuǎn)程服務(wù)
iTest=ITest.Stub.asInterface(service);
}
//斷開服務(wù)的時候
@Override
public void onServiceDisconnected(ComponentName name) {
//回收資源
iTest=null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initWidget();
//軟件一啟動就綁定服務(wù)
bindService();
}
private void bindService() {
Intent intent=new Intent();
intent.setComponent(new ComponentName("com.johnson.todo","com.johnson.todo.service.IRemoteService"));//第一個參數(shù)包名金拒,第二個參數(shù)文件名
bindService(intent,connection, BIND_AUTO_CREATE);
}
private void initWidget() {
tvSum = (TextView) findViewById(R.id.tv_sum);
et1 = (EditText) findViewById(R.id.et_1);
et2 = (EditText) findViewById(R.id.et_2);
btn= (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
add();
}
});
}
public void add(){
int num1 = Integer.parseInt(et1.getText().toString());
int num2 = Integer.parseInt(et2.getText().toString());
try {
int sum = iTest.add(num1, num2);
tvSum.setText(sum+"");
} catch (RemoteException e) {
e.printStackTrace();
tvSum.setText("RemoteException:"+e.toString());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
}