Android 进程通信(AIDL)
通过一段时间的学习,对AIDL有了一个初步的认识,最终实现了通信功能,以免忘记特此记录。
介绍:
利用AIDL(Android Interface Definition Language)实现APP间的通信(同一个手机上两个APP之间的通信),通过下列方法可以实现ClientAPP发送信息,ServerAPP接收信息。所以需要开发两个APP。
思路:
AIDL的实现思路是在ServerAPP上配置好AIDL相关信息以及相关的Service,让ClientAPP去绑定ServerAPP的服务,通过ServerAPP中的onBind返回AIDL的控制接口,然后就可以在ClientAPP中操作相关方法和ServerAPP进行通信。
两个APP都需要的配置:
1. 设置序列化对象Info.java实现 Parcelable,内容我们只传一句话,更多的自己去实现(代码1)
2. 配置AIDL相关文件Info.aidl MessageCenter.aidl,Info.aidl和Info.java需要同一个路径名(代码2)
3. 在build.gradle文件android{}中添加文件路径,以免aidl和java文件相互寻找不到(代码3)
ClientAPP需要的配置:
1. 与服务端建立连接(代码4)
2. 添加点击事件,调用服务端的方法(代码5)
ServerAPP需要的配置:
1. 配置AIDLService文件(代码6)
2. 在manifest.xml文件中配置Service(代码7)
3. 在MainActivity中启动Service(代码8)
注意:如果实现不了通讯,问题无非两种
1. AIDL和java文件的路径配置问题,有问题可以BD,网上很多解决方法
2. 绑定Service出现问题,就是ClientAPP没有绑定到ServerAPP的service
intent.setAction()和intent.setPackage()的设置出现问题
代码1:
public class Info implements Parcelable {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Info() {
}
public Info(Parcel in) {
content = in.readString();
}
public static final Creator<Info> CREATOR = new Creator<Info>() {
@Override
public Info createFromParcel(Parcel in) {
return new Info(in);
}
@Override
public Info[] newArray(int size) {
return new Info[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(content);
}
public void readFromParcel(Parcel dest) {
//注意,此处的读值顺序应当是和writeToParcel()方法中一致的
content = dest.readString();
}
@Override
public String toString() {
//打印做成Json格式
return "Info"+"{"+"content:"+content+"}"
}
}
代码2:
Info.aidl文件:
package com.clearliang.myaidlclient;
parcelable Info;//引入序列化的类
MessageCenter.aidl文件:
package com.clearliang.myaidlclient;
import com.clearliang.myaidlclient.Info;
interface MessageCenter {
//所有的返回值前都不需要加任何东西,不管是什么数据类型
List<Info> getInfo();
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定
Info addInfo(inout Info info);
}
代码3:
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/aidl']
resources.srcDirs = ['src/main/java', 'src/main/aidl']
aidl.srcDirs = ['src/main/aidl']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
}
}
代码4:
//尝试与服务端建立连接
private void attemptToBindService() {
Intent intent = new Intent();
intent.setAction("com.clearliang.myaidlserver");
intent.setPackage("com.clearliang.myaidlserver");//应用包名
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(getLocalClassName(), "service connected");
messageCenter = MessageCenter.Stub.asInterface(service);//拿到ServerAPP的AIDL控制接口
mBound = true;
if (messageCenter != null) {
try {
mInfoList = messageCenter.getInfo();
Log.e(getLocalClassName(), mInfoList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(getLocalClassName(), "service disconnected");
mBound = false;
}
};
注意:别忘了在onStop中解绑服务unbindService(mServiceConnection);
代码5
public void addMessage(String content) {
//如果与服务端的连接处于未连接状态,则尝试连接
if (!mBound) {
attemptToBindService();
Toast.makeText(this, "当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show();
return;
}
if (messageCenter == null) return;
Info info = new Info();
info.setContent(content);
try {
messageCenter.addInfo(info);
Log.e(getLocalClassName(),"客户端:"+ info.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
代码6
public class AIDLService extends Service {
public final String TAG = this.getClass().getSimpleName();
private List<Info> messages = new ArrayList<>();
private final MessageCenter.Stub messageCenter = new MessageCenter.Stub() {
@Override
public List<Info> getInfo() throws RemoteException {
synchronized (this) {
Log.e(TAG, "getInfo invoking getInfo() method , now the list is : " + messages.toString());
if (messages != null) {
return messages;
}
return new ArrayList<>();
}
}
@Override
public Info addInfo(Info message) throws RemoteException {
synchronized (this) {
if (messages == null) {
messages = new ArrayList<>();
}
if (message == null) {
Log.e(TAG, "message is null in In");
message = new Info();
}
if (!messages.contains(message)) {
messages.add(message);
}
Log.e(TAG, "客户传来了数据" + messages.toString());
Info mInfo = new Info();
mInfo.setContent("服务端做了修改:" + message.getContent() + "time:" + (System.currentTimeMillis()));
return mInfo;
}
}
};
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString()));
return messageCenter;//这里给ClientAPP提供AIDL管理接口的返回
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
代码7
<service
android:name=".AIDLService"
android:exported="true">
<intent-filter>
<action android:name="com.clearliang.myaidlserver"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
代码8
public class MainActivity extends AppCompatActivity {
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent=new Intent(this,AIDLService.class);
startService(intent);
}
//别忘了停止服务
@Override
protected void onDestroy() {
super.onDestroy();
intent = new Intent(this,AIDLService.class);
stopService(intent);
}
}