AIDL(Android接口描述語言)
aidl是 Android Interface definition language的縮寫,一看就明白妹沙,它是一種android內(nèi)部進程通信接口的描述語言梗夸,通過它我們可以定義進程間的通信接口。AIDL的作用是讓你可以在自己的APP里綁定一個其他 進程 的service。這里希望大家明白一點(Android中的Service和其調(diào) 用者既可以在同一個App中一喘,也可以在不同的App)
AIDL用法
聲明 :我在這里用AS創(chuàng)建項目可能和ES有點流程上的區(qū)別,相對而言AS更簡單了嗜暴。
在這里我們先用兩個應用間跨進程通信借以說明凸克。創(chuàng)建一個服務端AIDLServerTest,創(chuàng)建一個客戶端AIDLTest闷沥。
-
AIDLServerTest
首先我們在服務端中創(chuàng)建一個Calculate.aidl文件萎战。具體方法如下:
創(chuàng)建完成后我們給這個計算器(Calculate.aidl)添加加、減舆逃、乘蚂维、除的方法代碼如下:
package com.bsoft.aidlservertest;
// Declare any non-default types here with import statements
interface Calculate {
float addition(float arg1,float arg2);
float subtraction(float arg1,float arg2);
float multiplication(float arg1,float arg2);
float division(float arg1,float arg2);
}
這些做完之后我們需要手動構建下項目這是AS和ES有區(qū)別的地方戳粒,不會自動重構“Build----->Make Project”。
緊接著我們創(chuàng)建一個Service來提供我們的這些操作供外部應用使用虫啥,代碼如下:
/**
* Created by 泅渡者
* Created on 2017/9/22.
*/
public class CalculateUtils extends Service {
Binder mBinder = new Calculate.Stub(){
@Override
public float addition(float arg1, float arg2) throws RemoteException {
KLog.d("計算中");
return arg1+arg2;
}
@Override
public float subtraction(float arg1, float arg2) throws RemoteException {
KLog.d("計算中");
return arg1-arg2;
}
@Override
public float multiplication(float arg1, float arg2) throws RemoteException {
KLog.d("計算中");
return arg1*arg2;
}
@Override
public float division(float arg1, float arg2) throws RemoteException {
KLog.d("計算中");
return arg1/arg2;
}
};
@Override
public void onCreate() {
super.onCreate();
KLog.d("被執(zhí)行");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
KLog.d("被執(zhí)行");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
KLog.d("被執(zhí)行");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
KLog.d("被執(zhí)行");
return super.onUnbind(intent);
}
}
- 這里我只是演示Service的使用蔚约,并沒有做詳細的處理。
做完這些我們的服務端就以經(jīng)完成了涂籽,但別忘了注冊(這里我對Service又起了 一個進程苹祟,主要是防止因方法操作時間過長而造成服務端的ANR)
<service
android:name=".CalculateUtils"
android:process=":remote">
<intent-filter>
<action android:name="com.bsoft.aidlservertest.CalculateUtils" />
</intent-filter>
</service>
- AIDLTest
首先我們需要將服務端中的AIDL文件拷貝導當前項目目錄:
如下:
接著我們來看看怎么調(diào)用到另一個APP的中的工具呢?
代碼如下
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText edt_arg1, edt_arg2;
private TextView tv_solution;
private Button btn_submit;
private Calculate mService;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = Calculate.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edt_arg1 = (EditText) findViewById(R.id.edt_arg1);
edt_arg2 = (EditText) findViewById(R.id.edt_arg2);
btn_submit = (Button) findViewById(R.id.btn_submit);
tv_solution = (TextView) findViewById(R.id.tv_solution);
btn_submit.setOnClickListener(this);
Intent intent = new Intent();
intent.setAction("com.bsoft.aidlservertest.CalculateUtils");
intent.setPackage("com.bsoft.aidlservertest");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_submit:
float arg1 = Float.parseFloat(edt_arg1.getText().toString());
float arg2 = Float.parseFloat(edt_arg2.getText().toString());
float solution;
try {
solution = mService.multiplication(arg1, arg2);
tv_solution.setText(solution + "");
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mConnection != null) {
unbindService(mConnection);
}
}
}
注:如果提示說你的AIDL找不到评雌,說明你的包路徑不對树枫。
我們來看下(先啟動服務端,在啟動客戶端)客戶端運行結果:
/com.bsoft.aidlservertest:remote D/CalculateUtils.java: [ (CalculateUtils.java:49)#onCreate ] 被執(zhí)行
/com.bsoft.aidlservertest:remote D/CalculateUtils.java: [ (CalculateUtils.java:62)#onBind ] 被執(zhí)行
/com.bsoft.aidlservertest:remote D/CalculateUtils.java: [ (CalculateUtils.java:35)#multiplication ] 計算中
/com.bsoft.aidlservertest:remote D/CalculateUtils.java: [ (CalculateUtils.java:68)#onUnbind ] 被執(zhí)行
這里并不是服務端APP的進程而是Service的指定進程
“com.bsoft.aidlservertest:remote”景东,說明我們的客戶端已經(jīng)成功鏈接到服務端并進行了運算操作砂轻。
并且當onUnbind執(zhí)行時將服務端的Service進行了銷毀操作。
Messenger基于消息的進程間通信
Messenger:允許實現(xiàn)基于消息的進程間通信的方式斤吐。
說白了也是用來提供跨進程通信的東東搔涝,但是不用我們?nèi)ゾ帉慉IDL。
我們先用圖來理解下它運行的過程:
好的我們來創(chuàng)建這個實例項目:
- 服務端MessengerService代碼如下
/**
* Created by 泅渡者
* Created on 2017/9/22.
*/
public class MessengerService extends Service {
private static final int FLAG = 0x110;
private Messenger messenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msgfromClient) {
Message messageToClient = Message.obtain(msgfromClient);
switch (msgfromClient.what) {
case FLAG:
KLog.d("服務端接收導數(shù)據(jù)"+msgfromClient.arg1+"&&"+msgfromClient.arg2);
messageToClient.what = FLAG;
try {
//模擬耗時
Thread.sleep(2000);
messageToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2;
msgfromClient.replyTo.send(messageToClient);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
});
@Override
public void onCreate() {
super.onCreate();
KLog.d("執(zhí)行");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
KLog.d("執(zhí)行");
return messenger.getBinder();
}
}
<service
android:name=".MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.bsoft.messengerserver"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
這樣我們的服務端就已經(jīng)創(chuàng)建完畢(我們設置服務是隱式自啟動和措,不用再去手動啟動服務)
- 客戶端
public class MainActivity extends AppCompatActivity {
private static final int FLAG = 0x110;
private Messenger mService;
private boolean isConn = false;
private TextView tv_test;
private Button btn_test;
/**
* 客戶端Messenger
*/
private Messenger messenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case FLAG:
KLog.d("客戶端收到服務端處理的結果:"+msg.arg2);
tv_test.setText("20+10="+msg.arg2);
break;
}
}
});
/**
* 連接服務端 Messenger
*/
private ServiceConnection mConnect = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
isConn = true;
KLog.d("鏈接服務端成功");
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
isConn = false;
KLog.d("鏈接服務端失敗");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ServiceInvoked();
tv_test = (TextView) findViewById(R.id.tv_test);
btn_test = (Button) findViewById(R.id.btn_test);
btn_test.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msgFromClient = Message.obtain(null, FLAG, 20, 10);
msgFromClient.replyTo = messenger;
if (isConn) {
//往服務端發(fā)送消息
try {
KLog.d("給服務端發(fā)送數(shù)據(jù):"+msgFromClient.arg1+"&&"+msgFromClient.arg2);
mService.send(msgFromClient);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
private void ServiceInvoked() {
final Intent intent = new Intent();
intent.setAction("com.bsoft.messengerserver");
intent.setPackage("com.bsoft.messengerserver");
bindService(intent, mConnect, Service.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnect);
}
}
我們接下來看看運行結果:(首先啟動服務端体谒,再切掉,然后啟動客戶端)
- 客戶端日志及結果
D/MainActivity.java: [ (MainActivity.java:52)#onServiceConnected ] 鏈接服務端成功
D/MainActivity.java: [ (MainActivity.java:79)#onClick ] 給服務端發(fā)送數(shù)據(jù):20&&10
D/MainActivity.java: [ (MainActivity.java:37)#handleMessage ] 客戶端收到服務端處理的結果:30
- 服務端日志
D/MessengerService.java: [ (MessengerService.java:49)#onCreate ] 執(zhí)行
D/MessengerService.java: [ (MessengerService.java:55)#onBind ] 執(zhí)行
D/MessengerService.java: [ (MessengerService.java:29)#handleMessage ] 服務端接收導數(shù)據(jù)20&&10
上面就是我們客戶端跟服務端的通信臼婆,如果喜歡研究的話大可以去看看所謂的Messenger 只不過是對AIDL的封裝而已抒痒。
這里如果我們需要通信的數(shù)據(jù)涉及對象時需要進行序列化。