在我们的项目中,有时会需要使用到aidl,主要还是为了进程之间的通信,而这次,我在项目中也有了进程间通信的需求,所以,我抽时间了解了一下关于aidl的使用
网上这方面资料很多,我就针对我测试的demo做一下总结了
首先是我的项目的运行结果
然后是对于我的类的说明
我将进程间的交互写在了一个项目里面,主要还是因为我再实际项目中也是要用在一个项目中的缘故
其中的BaseTypeActivity就是我上面操作视频里面进入的最后的界面
那么,可以先来看看写法,
一、进程间通讯的环境要求
既然要进行进程通讯,那么肯定需要配置好一定的先决条件,那么条件是什么呢?
使用aidl进行进程间通讯,我们我要有通信的数据、通信的方法,那么对于数据和方法,在写入具体内容之前是否有要求呢,当然是有的
如果是不同项目之间的通讯,那么我们需要在两个项目中,针对通讯的方法和bean类必须都声明一下,并且报名类名必须一样,当然,我自己写的这个是不需要的,因为我就写在了一个项目中
二、进程间通讯的数据
首先,既然要进行进程间通讯,最基本的就是要可以传递数据,除了最基本的基本类型之外,传递自定义类就显得尤为重要了
那么对于自定义类的传递有哪些要求呢?
服务端(数据提供端)
1、实现Parcelable序列化接口,不实现就会在gen下生成的文件中报错,而且实现Serializable也不行
2、声明这个bean的aidl文件,这样才能在其他的aidl文件中作为参数
声明的方式倒是十分的简单,只需要这样就行了,例如对User类声明一个User.aidl文件,然后在文件内
写上
parcelable User;
就这么一句就够了
访问端
把服务端所有的数据方面的代码复制一份就行了
三、进程间通讯的方法
服务端(数据提供端)
总的来说,就是可以让另一个进程通过调用某个方法来获取到另一个进程的参数返回,那么对于这个方法的生命
1、使用aidl文件声明,并且必须写成interface
2、aidl接口类中使用到的自定义类,参考上面进程间通讯的数据的要求
3、需要写类来实现aidl中声明的 接口类.Stub
4、需要在Service的onBind方法中返回实现上一条的对象的实例
客户端(访问端)
1、创建ServiceConnection对象,可在onServiceConnected方法中获取到服务端实例化的通讯类对象
2、通过bindService方法访问服务端
3、通过unbindService方法断开服务端,但是,这里会发现即使调用了unbindService方法还是可以获取到服务端数据,不过这里我没有深究下去
那么在基本需要了解的之后就是实际代码了
服务端:
数据部分:
首先是需要传递的对象User
public class User
implements Parcelable
//implements Serializable
{
private int id;
private String username;
private String password;
public User() {
super();
}
public User(int id, String username, String password) {
super();
this.id = id;
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public boolean equals(Object o) {
User us=(User)o;
if(this.username.equals(us.username)&&this.password.equals(us.password))
{
return true;
}
else
{
return false;
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
Log.i("main", "客户端User被序列化");
dest.writeInt(id);
dest.writeString(username);
dest.writeString(password);
}
public static final Parcelable.Creator<User> CREATOR=new Creator<User>() {
@Override
public User[] newArray(int size) {
return new User[size];
}
@Override
public User createFromParcel(Parcel source) {
Log.i("main", "客户端User被反序列化");
return new User(source.readInt(), source.readString(),
source.readString());
}
};
}
可以看到User是实现了Parcelable接口的
然后是User的aidl声明User.aidl
parcelable User;
方法类部分:
然后是传递User的aidl类,IGetMsg.aidl
package com.example.aidlservicedemo.domain;
import com.example.aidlservicedemo.domain.Message;
import com.example.aidlservicedemo.domain.User;
interface IGetMsg{
User getMes();
}
接下来是aidl接口的实现类
public class MsgBinder extends Stub{
@Override
public User getMes() throws RemoteException {
return new User(-1, "xiaobai", "mima");
}
}
实现之后需要在Service的onBind方法返回
public class CustomTypeService extends Service {
private static final String TAG = "main";
private MsgBinder msgBinder=null;
public class MsgBinder extends Stub{
@Override
public User getMes() throws RemoteException {
return new User(-1, "xiaobai", "mima");
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return msgBinder;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
msgBinder=new MsgBinder();
Log.i(TAG, "CustomTypeService:onCreate进程名:" + ProcessTool.getCurProcessName(this));
}
@Override
public void onDestroy() {
msgBinder=null;
super.onDestroy();
}
}
到了这里,服务端的代码就完成了
接下来是客户端部分:
数据部分:
这里和服务端是一样的,直接拷贝过来就行
逻辑方法部分:
首先需要实现ServiceConnection
private IGetMsg getMsg;
private final String TAG="main";
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
getMsg = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
getMsg = IGetMsg.Stub.asInterface(service);
}
};
可以看到这里在onServiceConnected部分获取到了服务端传递过来的
通讯类对象
然后是开始绑定和取消绑定的方法
/**
* 开始服务
*/
private void startService() {
Intent service = new Intent();
service.setAction("cn.bgxt.Service.CUSTOM_TYPE_SERVICE");
bindService(service, conn, BIND_AUTO_CREATE);
Toast.makeText(CustomTypeActivity.this, "绑定服务成功", Toast.LENGTH_SHORT).show();
}
/**
* 停止服务
*/
private void endService() {
unbindService(conn);
Toast.makeText(CustomTypeActivity.this, "解除绑定服务成功", Toast.LENGTH_SHORT).show();
}
那么,先决条件都满足之后,就可以获取服务端传递过来的数据了
<span style="font-size:18px;">/**
* 获取其他线程服务数据
*/
private void getServiceDate(){
try {
User user=getMsg.getMes();
Toast.makeText(CustomTypeActivity.this, "id:" + user.getId() + ",name:" + user.getUsername() + ",password:" + user.getPassword(), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(CustomTypeActivity.this, "获取数据出错", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}</span>
到了这里,进程间通讯就完成了
其实写到获取数据方法的时候,我想到一个问题,那就是如果我们跨进程获取的数据需要在回调中才能获取,比如一个特殊的情况没有办法在返回值返回该怎么办?
于是我针对这种需求,试了一下,之后成功了,其实就是在回调的方法内需要客户端再传入一个接口而已
package com.example.aidlservicedemo.domain;
import com.example.aidlservicedemo.domain.Message;
import com.example.aidlservicedemo.domain.User;
import com.example.aidlservicedemo.domain.CallBack;
interface IGetMsg{
void getMes(in CallBack callback);
}
先是获取数据的方法要求传入接口
CallBack.aidl
package com.example.aidlservicedemo.domain;
import com.example.aidlservicedemo.domain.User;
interface CallBack{
void getDatas(in User user);
}
然后就是获取数据的地方
/**
* 获取其他线程服务数据
*/
private void getServiceDate(){
try {
getMsg.getMes(new Stub() {
@Override
public void getDatas(User user) throws RemoteException {
Log.i(TAG, "这里获取到回调的User对象:" + "id:" + user.getId() + ",name:" + user.getUsername() + ",password:" + user.getPassword());
}
});
// Toast.makeText(CustomTypeActivity.this, "id:" + user.getId() + ",name:" + user.getUsername() + ",password:" + user.getPassword(), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(CustomTypeActivity.this, "获取数据出错", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
到这里,比较基本的数据间通信就完成了
其实,我这次本来想把用handler进程间通信一起看了,不过光顾着玩来不及了,所以这篇就到这里了,Handler的进程间通信打算下次再写了,果然人就是懒了啊