Android绑定多个aidl,android aidl 多`module`版的实现
多module版,pojo類型數(shù)據(jù)的雙向傳遞 [service client]
android中如何進(jìn)行跨進(jìn)程通信的?
aidl是什么?
android中如何通過aidl實(shí)現(xiàn)跨進(jìn)程通信?
最簡(jiǎn)單的aidl如何實(shí)現(xiàn)?
多module之間如何通過aidl進(jìn)行通信?
單module實(shí)現(xiàn)aidl和多module實(shí)現(xiàn)aidl有何區(qū)別?
多App之間如何通過aidl進(jìn)行通信?
以上這些問題,我不打算全部回答。因?yàn)槲乙膊恢涝趺椿卮稹?/p>
關(guān)于第一個(gè)問題,和第二個(gè)問題,我相信官方文檔以及一些大神的博客已經(jīng)有了很詳盡的介紹,這里我就贅述了。
第三個(gè)問題 android中如何通過aidl實(shí)現(xiàn)跨進(jìn)程通信? 這個(gè)問題,還是太寬泛了,我也不回答了。
關(guān)于 如何實(shí)現(xiàn)最簡(jiǎn)單的aidl,請(qǐng)看這篇
好了,現(xiàn)在來本篇的重點(diǎn) 多module之間如何通過aidl進(jìn)行通信?
那我們就一步步開始吧。
后面的問題呢?別急啊...慢慢來。
關(guān)于“多module之間如何通過aidl進(jìn)行通信”我準(zhǔn)備分3個(gè)小點(diǎn)來說明:
- 如何實(shí)現(xiàn)多`module`之間,基本類型的數(shù)據(jù)的單向傳遞 [service --> client]
- 如何實(shí)現(xiàn)多`module`之間,自定義類型的`pojo`對(duì)象的單向傳遞 [service --> client]
- 如何實(shí)現(xiàn)多`module`之間,自定義類型的`pojo`對(duì)象的雙向傳遞 [service client]
從代碼開始:
首先,我新建一個(gè)android project,由于我使用的是android studio,所以默認(rèn)新建的項(xiàng)目就是一個(gè)安卓項(xiàng)目。
新建完成項(xiàng)目之后,默認(rèn)會(huì)生成一個(gè)module名為app。
然后,我會(huì)再建兩個(gè)module,名為service和aidl。
關(guān)于如何在android studio中新建一個(gè)module,這個(gè)大家都知道的吧。其中一種方法是:[菜單欄 --> File --> New --> New Module... --> Android Liarbry ]
好了,現(xiàn)在準(zhǔn)備工作完成了。多module已經(jīng)建立起來了。
解釋一下service是用來作為服務(wù)的,讓app去調(diào)用的。aidl是專門用來存放.aidl文件以及對(duì)應(yīng)的pojo類的。
接下來,我們?nèi)?shí)現(xiàn)一下服務(wù)吧,不然跨進(jìn)程通信是沒法建立起來的。
1.在service所在的module中,我新建一個(gè)類繼承android.app.Service,比如RemoteService。看起來差不多這個(gè)樣子:
public class RemoteService extends Service {
public RemoteService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
2.現(xiàn)在我們?nèi)バ薷囊幌虑鍐挝募W孯emoteService處在一個(gè)單獨(dú)的進(jìn)程。為什么要這么干?因?yàn)槿绻恍薷?#xff0c;那么無論是在哪個(gè)module實(shí)現(xiàn)的Service都是在主進(jìn)程的。 好了,現(xiàn)在我們看一下修改之后的當(dāng)前服務(wù)所在的節(jié)點(diǎn)的樣子:
android:name=".RemoteService"
android:enabled="true"
android:exported="true"
android:process=":remote" />
好了,我們?yōu)閷?shí)現(xiàn)跨進(jìn)程通信又跨出了一步。因?yàn)楝F(xiàn)在的確有多個(gè)進(jìn)程了。而且有多個(gè)module了。
3.現(xiàn)在呢,我們就得去定義.aidl文件了。
為什么現(xiàn)在就要定義.aidl文件呢? 因?yàn)槲覀冎?#xff0c;跨進(jìn)程通信本質(zhì)上是通過bindService的方法綁定一個(gè)遠(yuǎn)程服務(wù),以便實(shí)現(xiàn)數(shù)據(jù)的交互。而跨進(jìn)程的,內(nèi)存又無法共享,可以通過已知的共享內(nèi)存IBinder去實(shí)現(xiàn)跨進(jìn)程的數(shù)據(jù)交互。ps:這個(gè)解說可能存在錯(cuò)誤,請(qǐng)大家不要深信。
4.那么,我們準(zhǔn)備通過跨進(jìn)程傳遞什么呢?假設(shè),我現(xiàn)在想通過aidl傳遞一個(gè)500以內(nèi)的隨機(jī)數(shù)給調(diào)用者。那么,.aidl差不多長(zhǎng)這樣的:
// RemoteBinder.aidl
package com.pythoncat.aidl;
// Declare any non-default types here with import statements
interface RemoteBinder {
/**
* 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);
int getResult();
}
**注意:這個(gè).aidl文件是在aidl所在module中定義的。**至于能不能直接在sevcie所在module中定義,我猜測(cè)也是可以的,但是沒有去驗(yàn)證。放在一個(gè)單獨(dú)的module中的好處就是,以后查閱起來方便。
5.現(xiàn)在,我們定義好了RemoteBinder.aidl,然后rebuild一下工程。之后,會(huì)自動(dòng)生成一些類,這些我就不去深究了,因?yàn)楹椭黝}無關(guān)。
6.rebuild完成之后,我們?nèi)ネ晟苿偛哦x的RemoteService。重寫onBind()方法。完善之后的RemoteService差不多長(zhǎng)這樣的:
public class RemoteService extends Service {
public RemoteService() {
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
private class MyBinder extends RemoteBinder.Stub{
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int getResult() throws RemoteException {
return new Random().nextInt(500);
}
}
}
現(xiàn)在差不多大功告成了,就等著調(diào)用者來調(diào)用了。
7.現(xiàn)在我們?nèi)pp所在module。這里面默認(rèn)給我們提供了一個(gè)MainActivity。但是我不打算對(duì)它做什么。我給它改名為L(zhǎng)auncherActivity。并且在里面添加兩個(gè)按鈕,準(zhǔn)備讓他們分別實(shí)現(xiàn)界面的跳轉(zhuǎn)。第二個(gè)按鈕點(diǎn)擊之后就跳轉(zhuǎn)到AidlActivity。當(dāng)然這個(gè)AidlActivity也是在app所在module的,而且是剛剛新建的。
8.在AidlActivity里面呢,我準(zhǔn)備弄一個(gè)textview,用于顯示,將來通過aidl獲取的500以內(nèi)的隨機(jī)數(shù)。,和一個(gè)按鈕,按鈕的點(diǎn)擊就是觸發(fā)獲取的條件。
9.好了,UI部分算是完成了。現(xiàn)在呢,我們先讓我們的AidlActivity去綁定服務(wù)。怎么去綁定一個(gè)服務(wù),相信大家都會(huì)的。現(xiàn)在呢,我們就來看一下,綁定服務(wù)之后,AidiActivity長(zhǎng)什么樣子的:
public class AidlActivity extends AppCompatActivity {
private ServiceConnection mConn;
private RemoteBinder mRemoteBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
TextView tvShowResult = (TextView) findViewById(R.id.aidl_show_tv);
TextView tvParcelable = (TextView) findViewById(R.id.aidl_show_parcelable_tv);
tvParcelable.setText(getString(R.string.show_about_parcelable_service, ""));
tvShowResult.setText(getString(R.string.show_about_normal_service, ""));
Button btnExecute = (Button) findViewById(R.id.aidl_ui_btn);
btnExecute.setOnClickListener(v -> {
if (mRemoteBinder != null) {
try {
mRemoteBinder.setResult(1024);
int result = mRemoteBinder.getResult();
tvShowResult.setText(getString(R.string.show_about_normal_service, result));
LogUtils.e("aidl result===" + result);
} catch (RemoteException e) {
LogUtils.e("bind remote service fail...");
LogUtils.e(e);
}
}
});
mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteBinder = RemoteBinder.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mRemoteBinder = null;
}
};
bindService(new Intent(get(), RemoteService.class), mConn, Context.BIND_AUTO_CREATE);
}
public AppCompatActivity get() {
return this;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mConn != null) {
unbindService(mConn);
mConn = null;
}
}
}
需要注意的是IBinder對(duì)象的獲取方式:mRemoteBinder = RemoteBinder.Stub.asInterface(service);
ok,似乎一切已經(jīng)完成了。那么我們就跑起來吧。... 果不其然,我們從LaunchrActivity界面進(jìn)到AidlActivity先,然后,我們每點(diǎn)一次按鈕,textview上就出現(xiàn)一個(gè)500以內(nèi)的隨機(jī)數(shù),幾乎每次都不相同。
這么看來,我們已經(jīng)實(shí)現(xiàn)了多module之間的aidl通信。
-的確,剛才已經(jīng)實(shí)現(xiàn)了。但是剛才的實(shí)現(xiàn)僅僅是數(shù)據(jù)的單向傳遞[service-->client],而且是基本類型的數(shù)據(jù)的單向傳遞。
-現(xiàn)在呢,我們開始第二小節(jié)的說明,也就是如何實(shí)現(xiàn)多module之間的pojo類型的數(shù)據(jù)的單向傳遞 [service --> client]
還是從代碼開始:
首先在aidl所在module中定義一個(gè)pojo。比如這個(gè)樣子:
public class Duck {
public String name;
public long id;
}
為什么是在aidl所在module中定義pojo,而不是service所在module? 因?yàn)?在這里定義是為了讓.aidl能夠找到對(duì)應(yīng)的pojo類。
如果在其他module中定義,就要讓其他module成為當(dāng)前moudle的依賴。ps:關(guān)于此段的說明,我不能保證正確性,需要通過代碼驗(yàn)證。
現(xiàn)在呢,就是要讓Duck實(shí)現(xiàn)Parcelable接口。至于怎么實(shí)現(xiàn),我只說一句:android studio有相關(guān)的插件,自動(dòng)生成Parcelable接口的實(shí)現(xiàn)。
然后,定義該pojo對(duì)應(yīng)的.aidl文件。差不多長(zhǎng)這樣子的:
// Duck.aidl
package com.pythoncat.aidl.bean;
// Declare any non-default types here with import statements
parcelable Duck;
注意包的對(duì)應(yīng)
接下來,就是定義傳輸pojo的接口方法了。比如:Duck getDuck();。那么,我們?nèi)バ陆ㄒ粋€(gè).aidl文件,映射一個(gè)Ibinder。里面有傳輸pojo的方法。ok,定義之后的新的.aidl差不多長(zhǎng)這樣的:
// RemoteBinder.aidl
package com.pythoncat.aidl;
// Declare any non-default types here with import statements
import com.pythoncat.aidl.bean.Duck;
interface RemoteBinder {
/**
* 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);
int getResult();
Duck getDuck();
}
再次rebuild項(xiàng)目。
之后,會(huì)提示你報(bào)錯(cuò)了。因?yàn)槟愕腞emoteService$MyBinder不是抽象類,并且有未實(shí)現(xiàn)的方法。那么我們就去實(shí)現(xiàn)該抽象方法。實(shí)現(xiàn)之后,Mybinder差不多長(zhǎng)這樣子:
public class MyBinder extends RemoteBinder.Stub {
private Duck duck;
private int result;
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int getResult() throws RemoteException {
if (result == 0) {
return new Random().nextInt(500);
} else {
return this.result;
}
}
@Override
public Duck getDuck() throws RemoteException {
if (this.duck == null) {
Duck d = new Duck();
d.id = 10086;
d.name = "DuckTang";
return d;
} else {
this.duck.name = this.duck.name + "&Jerry";
return this.duck;
}
}
}
ok,我們的服務(wù)算是搞定了,接下來就是看調(diào)用者AidlActivity了。那么,我們就去調(diào)用者中添加獲取pojo對(duì)象的方法,并顯示在textview中。差不多就是這樣子的:
Duck d = mRemoteBinder.getDuck();
tvParcelable.setText(getString(R.string.show_about_parcelable_service, d.toString()));
當(dāng)然我又新加了一個(gè)textview,這個(gè)也要告訴你嗎?
現(xiàn)在呢,完整的AidlActivity是這樣的:
package com.pythoncat.ipcorservice2.activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.TextView;
import com.apkfuns.logutils.LogUtils;
import com.pythoncat.aidl.RemoteBinder;
import com.pythoncat.aidl.bean.Duck;
import com.pythoncat.ipcorservice2.R;
import com.pythoncat.service.RemoteService;
public class AidlActivity extends AppCompatActivity {
private ServiceConnection mConn;
private RemoteBinder mRemoteBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
TextView tvShowResult = (TextView) findViewById(R.id.aidl_show_tv);
TextView tvParcelable = (TextView) findViewById(R.id.aidl_show_parcelable_tv);
tvParcelable.setText(getString(R.string.show_about_parcelable_service, ""));
tvShowResult.setText(getString(R.string.show_about_normal_service, ""));
Button btnExecute = (Button) findViewById(R.id.aidl_ui_btn);
btnExecute.setOnClickListener(v -> {
if (mRemoteBinder != null) {
try {
int result = mRemoteBinder.getResult();
tvShowResult.setText(getString(R.string.show_about_normal_service, result));
LogUtils.e("aidl result===" + result);
Duck d = mRemoteBinder.getDuck();
tvParcelable.setText(getString(R.string.show_about_parcelable_service, d.toString()));
LogUtils.e("aidl parcelable===" + d.toString());
} catch (RemoteException e) {
LogUtils.e("bind remote service fail...");
LogUtils.e(e);
}
}
});
mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteBinder = RemoteBinder.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mRemoteBinder = null;
}
};
bindService(new Intent(get(), RemoteService.class), mConn, Context.BIND_AUTO_CREATE);
}
public AppCompatActivity get() {
return this;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mConn != null) {
unbindService(mConn);
mConn = null;
}
}
}
似乎已經(jīng)結(jié)束了,那就跑起來吧。run app...。果不其然,我們的界面上看到了在Mybinder中定義的new Duck()對(duì)象。
現(xiàn)在,我們就完成第二小節(jié)的說明。完成了多module之間通過aidl進(jìn)行pojo類型的數(shù)據(jù)的單向傳遞 [service --> client]
但是,最后一個(gè)問題還沒有解決,就是雙向的傳遞 [service client]
好了,那我們就去實(shí)現(xiàn)一下吧。
首先,在RemoteBinder中新添加一個(gè)方法void setDuck(Duck d);。添加之后,差不多長(zhǎng)這樣的:
// RemoteBinder.aidl
package com.pythoncat.aidl;
// Declare any non-default types here with import statements
import com.pythoncat.aidl.bean.Duck;
interface RemoteBinder {
/**
* 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);
int getResult();
void setResult(in int result);
Duck getDuck();
void setDuck(in Duck duck); // in is ok
}
至于上面為什么要加上in,這個(gè)涉及到aidl中定向tag相關(guān)的知識(shí)點(diǎn),這里我不多介紹了。
再次rebuild項(xiàng)目。結(jié)束之后,發(fā)現(xiàn)又報(bào)錯(cuò)了,說你的MyBinder不是抽象類,而且有沒有實(shí)現(xiàn)的抽象方法void setDuck(Duck d)。于是,就實(shí)現(xiàn)一下。那么,現(xiàn)在。MyBinder長(zhǎng)這樣子:
public class MyBinder extends RemoteBinder.Stub {
private Duck duck;
private int result;
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int getResult() throws RemoteException {
if (result == 0) {
return new Random().nextInt(500);
} else {
return this.result;
}
}
@Override
public void setResult(int result) throws RemoteException {
this.result = result;
}
@Override
public Duck getDuck() throws RemoteException {
if (this.duck == null) {
Duck d = new Duck();
d.id = 10086;
d.name = "DuckTang";
return d;
} else {
this.duck.name = this.duck.name + "&Jerry";
return this.duck;
}
}
@Override
public void setDuck(Duck duck) throws RemoteException {
this.duck = duck;
}
}
ok,服務(wù)這邊算是結(jié)束了。接下來,去看調(diào)用者AidlActivity是如何去傳遞一個(gè)pojo對(duì)象給服務(wù)。看起來應(yīng)該是這樣子的:
if (mRemoteBinder != null) {
try {
mRemoteBinder.setResult(1024);
int result = mRemoteBinder.getResult();
tvShowResult.setText(getString(R.string.show_about_normal_service, result));
LogUtils.e("aidl result===" + result);
Duck duck = new Duck();
duck.name = "pythonCat";
duck.id = 12306;
mRemoteBinder.setDuck(duck);
Duck d = mRemoteBinder.getDuck();
tvParcelable.setText(getString(R.string.show_about_parcelable_service, d.toString()));
LogUtils.e("aidl parcelable===" + d.toString());
} catch (RemoteException e) {
LogUtils.e("bind remote service fail...");
LogUtils.e(e);
}
}
好了,現(xiàn)在一切結(jié)束了。跑起來吧。... 果然,和我們預(yù)想的一樣,現(xiàn)在界面顯示的我們傳遞過去的Duck對(duì)象。而不是,先前在服務(wù)中定義的Duck對(duì)象了。
那么,毫無疑問,我們完成了之前的問題。多module之間如何通過aidl實(shí)現(xiàn)數(shù)據(jù)的雙向傳遞。
哈哈哈哈哈,我們完成了。
然后呢?
多App之間如何進(jìn)行aidl?未完待續(xù)吧,或者沒有下文了。
總結(jié)
以上是生活随笔為你收集整理的Android绑定多个aidl,android aidl 多`module`版的实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: r语言x%3c-读取文件,R语言读写最灵
- 下一篇: android遍历拼接字符串,写个批处理