之前上一篇讲解到本地服务,本地服务只能在自身APP中Activity访问Service,调用Service里面到方法等操作
如果想A应用访问B应用里面的方法,属于跨进程调用,如果Android不特供这种跨进程间通讯等API,是不能实现的
Google Android 为了解决 A应用--->B应用 跨进程访问通讯,提供了一种机制,就是IBInder,这种IBinder机制是Google工程师加入进去的,以前的Linux里是没有这个机制的
bindService 会返回IBinder接口,IBinder就是Google工程师在为了解决这种跨应用跨进程通讯,IBinder还需要结合Aidl才能实现远程服务(跨进程跨应用通讯)
注意:⚠️以前本地服务是通过显示意图去绑定,现在远程服务由于无法拿到另外应用的字节码,只能隐士意图去绑定
Service2,作为服务端,需要把MyService暴露出去
<!-- 代表在应用程序里,当需要该service时,会自动创建新的进程。 android:process=":remote" 是否可以被系统实例化 android:enabled="true" 代表是否能被其他应用隐式调用 android:exported="true" --> <service android:name=".service.MyService3"> <intent-filter> <!-- 激活 MyService2 唯一name,不能重名--> <action android:name="liudeli.service2.service.MyService3" /> </intent-filter> </service>
Service2,传递的对象Student,需要实现 Parcelable 接口
⚠️注意:Student.java Student.aidl 包名必须一致

Service2,传递的对象Student,需要实现 Parcelable 接口
package liudeli.service2; import android.os.Parcel; import android.os.Parcelable; public class Student implements Parcelable { public int id; public String name; public int age; public String hobby; /** * 注意:构造方法的读取一定要和writeToParcel(写入)顺序一致 * @param in */ protected Student(Parcel in) { id = in.readInt(); name = in.readString(); age = in.readInt(); hobby = in.readString(); } public 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]; } }; @Override public int describeContents() { return 0; } /** * 注意:构造方法的读取一定要和writeToParcel(写入)顺序一致 * @param dest * @param flags */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeString(name); dest.writeInt(age); dest.writeString(hobby); } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", hobby='" + hobby + '\'' + '}'; } }
Service2,传递的对象Student,还需要在.aidl文件中声明是Parcelable
![]()
// Student.aidl package liudeli.service2; // Declare any non-default types here with import statements parcelable Student;
Service2,把逻辑都写在MyService
package liudeli.service2.service; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import liudeli.service2.IQueryStudent; import liudeli.service2.Student; public class MyService3 extends Service { @Override public IBinder onBind(Intent intent) { return new IQueryStudent.Stub() { @Override public Student queryStudentByID(int id) throws RemoteException { Student student = null; switch (id) { case 1: student = new Student(); student.id = 1; student.name = "张三"; student.age = 20; student.hobby = "喜欢画画"; break; case 2: student = new Student(); student.id = 2; student.name = "李连杰"; student.age = 46; student.hobby = "套路扎实,功夫厉害"; break; default: student = new Student(); student.id = 3; student.name = "梁小龙"; student.age = 54; student.hobby = "腿功厉害"; break; } return student; } }; } }
Service2,现在远程服务的AIdl语言接口的定义:
![]()
// IQueryStudent.aidl package liudeli.service2; // Declare any non-default types here with import statements import liudeli.service2.Student; interface IQueryStudent { /** * ID查询学生详情(学生对象) */ Student queryStudentByID(int id); }
注意:要把这些aidl文件,Student.java 文件 全部copy 到 -->Service1应用,要保证这些文件的命名 包名 两个工程 一模一样

----------------------------- 分割线 下面代码是 Service1 访问者相关的了
Service1,⚠️要把Service2 aidl 带包一起copy到Service1,保持aidl相关一模一样
Service1,绑定远程服务相关代码
package liudeli.service1; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.View; import android.widget.Toast; import liudeli.service2.IQueryStudent; import liudeli.service2.Student; public class RemoteActivity2 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_remote); bindServiceAction(); } /** * Activity初始化的时候绑定服务 */ private void bindServiceAction() { Intent intent = new Intent(); intent.setAction("liudeli.service2.service.MyService3"); // android 5.0以后直设置action不能启动相应的服务,需要设置packageName或者Component intent.setPackage("liudeli.service2"); bindService(intent, connection, BIND_AUTO_CREATE); } private IQueryStudent iQueryStudent; /** * 定义服务连接对象,用于连接远程服务 */ private ServiceConnection connection = new ServiceConnection() { /** * 服务连接成功 * @param name 可以获取到服务到完整信息 * @param service 服务那边返回到IBinder接口 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { // 这里和本地服务不同,本地服务是强制类型转换,远程服务直接使用代理完成 iQueryStudent = IQueryStudent.Stub.asInterface(service); } /** * 服务断开连接 * @param name */ @Override public void onServiceDisconnected(ComponentName name) { } }; /** * 查询远程服务里面的数据 * @param view */ public void queryRemoteService(View view) { if (null == iQueryStudent) { Toast.makeText(this, "绑定远程服务失败,无法查询", Toast.LENGTH_LONG).show(); return; } try { Student student = iQueryStudent.queryStudentByID(2); Toast.makeText(this, "查询成功:" + student.toString(), Toast.LENGTH_LONG).show(); } catch (RemoteException e) { e.printStackTrace(); Toast.makeText(this, "远程服务失败 远程异常", Toast.LENGTH_LONG).show(); } } /** * Activity结束时,记得一定要解绑服务,否则会报连接资源异常 */ @Override protected void onDestroy() { super.onDestroy(); unbindService(connection); } }
Layout布局相关:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="queryRemoteService" android:text="查询远程服务" /> </LinearLayout>
操作:

浙公网安备 33010602011771号