如果你閒着沒事兒幹,那麼你可以學習這個項目,自己可以玩的很開心。
aidl.im.one 和 aidl.im.two這兩個module是利用aidl實現的兩個可以聊天的app,不過是裝在同一個手機上的
適合超級無聊之人自己和自己聊天使用。
*二話不說,看我上圖*
AIDL :Android interface definition language,Android 接口描述語言。
Android studio:新建一個項目,新建兩個application module,目的是用這兩個app進行測試通信(以下稱
app1 和 app2 )。
一、兩個module中新建包名和文件名都一樣的aidl文件,本項目是IRemoteService.aidl,名稱和包名不一樣的話兩
邊都會找不到服務。
二、如果要通過服務傳遞自定義對象的話,那麼也需要定義該對象的aidl文件,本項目定義了UserMessage.aidl,和IRemoteService.aidl一樣,在兩個module中包名和文件名都一樣。
三、兩個module 中新建UserMessage.java(也可以是其他語言對象,看你用的是什麼語言了,比如可以是UserMessage.kt),也需要時一樣的包名和文件名。
四、接下來就是寫activity和service了,aidl.im.one中新建MainActivity和RemoteService類,位置和名稱就
隨便了。
(1)MainActivity
1) onCreate方法就可以直接註冊本app(app1)接受消息的服務
Intent intent2 = new Intent().setComponent(new ComponentName(
"com.chaoya.aidlimone",
"com.chaoya.aidlimone.RemoteService"));
bindService(intent2, mConnection2, Context.BIND_AUTO_CREATE);
在發送消息的方法裏判斷app2的服務有沒有連接上,沒連接上的話就去連接綁定,之所以沒有也在
onCreate方法中綁定是因爲同一個手機中沒法同時點擊打開兩個app,若是在onCreate中綁定的話,就會
找不到服務,導致綁定失敗,因爲app2還沒啓動,同樣其服務也沒啓動,所以是連接不成功的;可能有人
會問,爲什麼不先把app2啓動?如果先把app2啓動的話,app1啓動時確實可以連接上app2的服務,並且
app1的接受消息的服務也綁定成功,app1算是沒問題了,但是app2呢,app2是沒有連接上app1的服務的,
道理和先啓動app1是一樣的,不再贅述;這個時候想讓app2也連接上app1的服務,就需要app2重啓,但是
問題又來了,若app2重啓了,那麼app2自己的接受消息的服務也會重新綁定初始化,對象會變哦,內存地
址都不一樣了,這時候app1持有的還是那個一樣不存在的服務,如果這時app1調用發送消息服務,那麼就
會報錯,什麼錯呢,就是Android的android.os.DeadObjectException異常。
2)在發送點擊事件中綁定app2的服務
Intent intent1 = new Intent().setComponent(new ComponentName(
"com.chaoya.aidlimtwo",
"com.chaoya.aidlimtwo.RemoteService"));
bindService(intent1, mConnection1, Context.BIND_AUTO_CREATE);
注意:1)和2)中綁定的服務是不一樣的,一個是自己的接受消息的服務,一個是調用對方的遠程服務。
3)發送消息的服務具體操作
private ServiceConnection mConnection1 = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "onServiceConnected");
remoteService = IRemoteService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
這個對象就是bindService時傳入的監聽,在發送消息時判斷一下remoteService,爲null時再bindServi
ce一下。
發消息的代碼
if ("".equals(content.getText().toString().trim())) {
Toast.makeText(this, "請輸入信息", Toast.LENGTH_SHORT).show();
return;
}
if (remoteService == null) {
Toast.makeText(this, "服務正在啓動...", Toast.LENGTH_SHORT).show();
Intent intent1 = new Intent().setComponent(new ComponentName(
"com.chaoya.aidlimtwo",
"com.chaoya.aidlimtwo.RemoteService"));
bindService(intent1, mConnection1, Context.BIND_AUTO_CREATE);
return;
}
try {
remoteService.sendMessage(new UserMessage(content.getText().toString().trim()));
list.addFirst("女孩說:" + content.getText().toString().trim());
content.setText("");
adapter.notifyDataSetChanged();
} catch (RemoteException e) {
e.printStackTrace();
}
我這裏用了一個listview把發送和收到的消息都展示了
4)接受消息的服務的具體操作
RemoteService.InnerIBinder innerIBinder = (RemoteService.InnerIBinder) service;
RemoteService remoteService = (RemoteService) innerIBinder.getService();
remoteService.setCallBack(new RemoteService.CallBack() {
@Override
public void showMessage(UserMessage message) {
list.addFirst("男孩說:" + message.messageContent);
adapter.notifyDataSetChanged();
}
});
這裏通過回調的方式去獲取了service收到的消息,我這裏是直接加入集合並展示了。
(2)RemoteService,繼承自android.app.Service
1)定義一個內部類供本app調用
public class InnerIBinder extends IRemoteService.Stub {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException {
}
@Override
public void sendMessage(UserMessage message) throws RemoteException {
//將收到的消息回調給MainActivity,其實就是app2遠程調用的,對app1來說就是接受到的
callBack.showMessage(message);
}
public Service getService() {
return RemoteService.this;
}
}
2)onBind方法中直接返回new InnerIBinder();
3)定義一個回調接口
public interface CallBack{
void showMessage(UserMessage message);
}
4)設置回調方法
public void setCallBack(CallBack callBack){
this.callBack = callBack;
}
五、app2的代碼和app1幾乎一樣,除了調用服務的包名外。
六、本着真正開源的精神,代碼上傳GitHub了,特討厭把代碼傳C**N,下載還要錢,不喜歡,地址如下:
[https://github.com/xiaodouyaer/AIDLIM]
七、有寫的不對的地方,還請斧正。