跨进程通讯之AIDL-----不同应用程序之间跨进程
AIDL,通俗来说就是两个Android应用要进行通信,且不能通过网络云服务器的方式进行数据交互,只能调用本地函数库的机制来实现,这时Android系统提供AIDL的机制来实现Android的跨进程通讯(用户进程之间是相对封闭的,无法直接访问数据)。
我们先不管任何原理,把demo跑出来再说其他的:
准备材料:一个Service、一个Client、连接S—C的桥梁(AIDL文件)
第一步: 连接S—C的桥梁(AIDL文件),这个aidl文件是客户端和服务器端都需要的,在服务端或者客户端的项目中生成都可以,如果传递基本数据类型就直接使用,如果是引用数据类型,先声明这个实体类,项目包结构如下
①Person类中主要是实现Parcelable接口,代码如下
package com.testaidl.model;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by Administrator on 2018\10\31 0031.
*/
public class Person implements Parcelable {
private String name;
protected Person(Parcel in) {
name = in.readString();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
}
@Override
public String toString() {
return "Person{" +
"mName='" + this.getName() + '\'' +
'}';
}
}
②然后再项目的main结构下创建aidl文件夹,创建Person的aidl后缀文件,必须要和上面Person的包名(结构)相同,这个Person类很简单就是声明一下parcelable 接口,
③IMyAidl这个接口的方法是提供给C-S调用的,
// IMyAidl.aidl
package com.testaidl;
// 这个引用类型必须是全类名的才能使用
import com.testaidl.model.Person;
interface IMyAidl {
/**
* 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);
void addPerson(in Person person);
List<Person> getPersonList();
}
这样子,AIDL这个中间件就做好了,把它分别放到代表:客户端和服务器项目中(例如我们在客户端的项目中生成AIDL文件,然后copy给服务器,但是要注意包名必须完全一致,C-S两端都要一致的,有点童鞋会说我想将客户端或者服务端放到之前的项目中,这时包名是定好的,不方便修改怎么办,在与当前包名同级的地方创建Person类,这样就保证了C-S两端包名都是一致的)
第二部:创建服务端,在新的项目中copyAIDL文件(放到项目中main结构的aidl文件夹中),一定要注意包名相同!!!,然后在完全相同的包结构下复制Person这个实体类,编译一下程序,服务端其实就是Android四大组件中的Service,
package com.my_project.test_aidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import com.testaidl.IMyAidl;
import com.testaidl.model.Person;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2018\10\31 0031.
* 服务端 service
*/
public class MyAidlService extends Service {
private final String TAG = this.getClass().getSimpleName();
public ArrayList<Person> mPersons;
/**
* 创建生成的本地 Binder 对象,实现 AIDL 制定的方法
*/
private IBinder mIBinder = new IMyAidl.Stub() {
@Override
public void addPerson(Person person) throws RemoteException {
Log.e("11111111111",person.toString());
mPersons.add(person);
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List<Person> getPersonList() throws RemoteException {
return mPersons;
}
};
/**
* 客户端与服务端绑定时的回调,返回 mIBinder 后客户端就可以通过它远程调用服务端的方法,即实现了通讯
*
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
mPersons = new ArrayList<>();
Log.e(TAG, "MyAidlService onBind");
return mIBinder;
}
}
然后咱们再清单文件中声明service的时候要设置其action(这个名字可以随意取的):
第三步:创建客户端项目:同样的方式copyAIDL文件和Person实体类,这个是和服务端一样的,然后编译生成Stub,做好准备工作以后,在客户端上绑定这个服务,bingService(…)
package com.testaidl;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.testaidl.model.Person;
import java.util.List;
import java.util.Random;
/**
* 客户端client 代码
* */
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent1 = new Intent();
intent1.setPackage("com.my_project");
intent1.setAction("com.test_aidl.aidl");
bindService(intent1, mConnection, BIND_AUTO_CREATE);
final Button btn_test = findViewById(R.id.btn_test);
final TextView tv_test = findViewById(R.id.tv_test);
btn_test.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Random random = new Random();
Person person = new Person("shixin" + random.nextInt(10));
try {
mAidl.addPerson(person);
List<Person> personList = mAidl.getPersonList();
tv_test.setText(personList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private IMyAidl mAidl;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//连接后拿到 Binder,转换成 AIDL,在不同进程会返回个代理
mAidl = IMyAidl.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mAidl = null;
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}
这样客户端生成好了,可以通过客户端发消息给服务端,亲测服务端可以收到消息