本文实现的功能:
下图是客户端的截图
第一个button用于client程序绑定servcer程序的服务
edit用于用户输入学生的ID
第二个Button用于调用servcer程序的getStudent方法,获取学生的数据。学生的数据在server程序中,我们实现的是从client程序访问Server程序的数据,这就是用AIDL实现进程的通信,
第三个button用于取消绑定
下面是程序的实现步骤:
1、在服务端定义一个Student.class,并使其继承自Parcelable
//**1、**implements Parcelable,使这个类序列化,其中的数据才能在两个进程间传递
public class Student extends LitePalSupport implements Parcelable{
@Column(unique = true)
private int studentId;
private String name;
private double grade;
protected Student(Parcel in) {
//**4、**解包,读取其中的数据,读取顺序需要和写入的顺序一样
studentId = in.readInt();
name = in.readString();
grade = in.readDouble();
}
//**3、**创建 Creator<Student>类,并重写其中的方法
public static final Creator<Student> CREATOR = new Creator<Student>() {
//解包,读取包中的数据
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
public Student() {
}
@Override
public String toString() {
return "Student{" +
"id=" + studentId +
", name='" + name + '\'' +
", grade=" + grade +
'}';
}
public void setStudentId(int id) {
this.studentId = id;
}
public void setName(String name) {
this.name = name;
}
public void setGrade(double grade) {
this.grade = grade;
}
public int getStudentId() {
return studentId;
}
public String getName() {
return name;
}
public double getGrade() {
return grade;
}
//**2、**将当前数据打包,注意,之后的读数据的顺序需要和写数据一样
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(studentId);
dest.writeString(name);
dest.writeDouble(grade);
}
}
2、创建ISteudent.aidl,需要和Student在一个包中,直接new一个AIDL,会生成一个aidl包,ISteudent.aidl的包名和Student一样
package com.michal.getstudentservicer;
//1、需要手动import Student
import com.michal.getstudentservicer.Student;
//2、interface的public去掉
interface IStudentService {
Student getStudent(int id);
}
3、在ISteudent.aidl所在的包下,新建一个Student.aidl,new file>Student.aidl,与Student是一样的名称内容如下
package com.michal.getstudentservicer;
parcelable Student;
4、新建一个服务器端的服务,需要实现getStudent的方法
//**1、**继承Service
public class GetStudentServer extends Service {
public GetStudentServer() {
}
//5、客户端绑定服务端的服务之后会调用到这个方法,并返回StudentService对象给客户端,
//客户端得到这个对象之后就可以调用getStudent方法,此方法会调用刚才重新的getStudent方法,并将获取的Student对象返回给客户端
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e("michal","onBind");
return new StudentService();
}
//2、新建一个StudentService类,继承IstudentService.Stub
class StudentService extends IStudentService.Stub{
//**3、**重写getStudent方法,这是这个方法的真正实现,客户端调用的就是这个方法
@Override
public Student getStudent(int id) throws RemoteException {
//4、查询数据库中对应id的Student的数据,并返回给客户端
List<Student> student = LitePal.where("id=?",String.valueOf(id)).find(Student.class);
if (student.size()>0)
return student.get(0);
else {
return null;
}
}
}
}
5、服务端搞定,现在开始写客户端,客户端算是另一个程序(进程)
将服务端创建的Student,ISteudent.aidl,Student.aidl复制到客户端,注意两者的包名必须一样,我选择在客户端创建同样的包名,然后将三个文件的内容复制过去
6、在客户端创建getStudentActivity,并创建点击事件,包括绑定远程服务,调用远程服务的getStudent方法,取消绑定
public class GetStudentActivity extends AppCompatActivity {
private IStudentService studentService;
private EditText editText;
private ServiceConnection serviceConnection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_get_student);
editText = findViewById(R.id.student_id);
}
public void onBindRemoteService(View view) {}
public void invokeRemoteService(View view) {}
public void unBindRemoteService(View view) {}
}
7、实现onBindRemoteService方法
public void onBindRemoteService(View view) {
//1、如果serviceConnection为空,则创建一个新对象
if (serviceConnection==null){
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LogUtils.e("onconnection");
//4、首次绑定之后会触发onServiceConnected,在此处获取IstudentService对象,在后面的incoke方法中用这个对象调用getStudent方法
studentService = IStudentService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
//2、启动绑定服务,此处为隐式启动,需要在服务端设置一个intent-filter
Intent intent = new Intent();
intent.setAction("com.michal.getstudentservicer.GetStudentServer");
//3、设置远程服务端的包名,注意可能无法直接用new Intent(Action str),bindService()启动,因为不知道哪个版本开始不支持这种操作
intent.setPackage("com.michal.getstudentservicer");
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
LogUtils.e("绑定服务");
}else {
LogUtils.e("已绑定服务");
}
}
8、实现invokeRemoteService方法,调用服务端的getStudent方法,获取学生的数据
public void invokeRemoteService(View view) {
if (studentService!=null){
try {
//1、获取editext输入的ID,并判断有没有输入,如果长度为0,则说明用户没输入ID,不会执行下面
String meditText = editText.getText().toString();
if (meditText.length()==0){
Toast.makeText(this,"请输入ID",Toast.LENGTH_SHORT).show();
}else {
int id = Integer.parseInt(meditText);
if (id != 0){
//2、使用studentService对象调用getStudent方法,返回student对象
Student student = studentService.getStudentById(id);
if (student==null){
LogUtils.e("查询不到该ID");
}else {
LogUtils.e(student.toString());
}
}
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
程序源码地址:https://download.csdn.net/download/weixin_42456904/19305404