Android进程通信(AIDL快速实现inder进程通信)
程序员文章站
2022-05-01 19:17:25
AIDL概念Android提供的一种快速实现binder进程通信的工具,也可以不用AIDL,自己实现binder来达到同样的效果,但是会比较复杂,后面我会写文章来细说。AIDL支持的基本类型 : String,int,long,boolean,float,double,ArrayList,HashMap,Parcelable为什么要用AIDL因为可以让我们更轻松的使用binder,专注写client、service,而不必太关心ServiceManager、Binder驱动,那么问题又来了,...
AIDL概念
Android提供的一种快速实现binder进程通信的工具,也可以不用AIDL,自己实现binder来达到同样的效果,但是会比较复杂,后面我会写文章来细说。
AIDL支持的数据类型 : String,int,long,boolean,float,double,ArrayList,HashMap,Parcelable等
为什么要用AIDL
因为可以让我们更轻松的使用binder,专注写client、service,而不必关心ServiceManager、Binder驱动,那么问题又来了,为什么要用binder来进程通信呢?后续有文章单独来说,那问题又又来了,Android为什么需要进程通信呢?进程通信的方式有哪些呢?一个个问题是不是纷至沓来,感觉压的自己透不过气,一定要知道个所以然呢?客官莫急,且听我细细道来。但是当前第一步就是要学会用AIDL实现跨进程的通信!
第一步
新建AIDL文件,会在src/main下面自动新建一个叫aidl的文件夹
// Declare any non-default types here with import statements /**除了默认的基本类型,就是下面直接生成出来的方法自带的这6种类型不需要import之外,其他的都需要手动import
- 其他类型包括下面几种:
*List 接口(会自动将List接口转为 ArrayList),且集合的每个元素都必须要么是基本类型,要么是Parcelable实现类
*Map 接口(会自动将 Map 接口转为 HashMap),且每个元素的 key 和 value 要么是基本类型,要么是Parcelable实现类
*Parcelable 的实现类
*AIDL 接口本身
*/ import com.ly.aidltest.Student; interface IMyAidlInterface { /**
* 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); //定义两个方法,也就是提供给客户端的服务 List<Student> getStudent(); //这里的in 是有讲究的 void addStudent(in Student stu); }
注意事项
所有非基本类型的参数都需要标签来表明这个数据的去向:
- in,表示此变量由客户端设置
- out,表示此变量由服务端设置
- inout,表示此变量可由客户端和服务端设置
此时可以rebuild一下
第二步
定义上面AIDL文件用到的java对象
public class Student implements Parcelable { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } protected Student(Parcel in) { name = in.readString(); age = in.readInt(); } 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 String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); } }
除了定义Java对象之外,还需要一步,复制第一步新建的xxx.aidl文件,重命名为java对象同样的名字:
第三步
新建service服务端
public class MyService extends Service { private List<Student> list = new ArrayList<>(); private static final String TAG = "MyService"; @Override public void onCreate() { super.onCreate(); Log.e(TAG, "onCreate: "); list.add(new Student("小明", 12)); list.add(new Student("小红", 13)); list.add(new Student("小军", 14)); } private IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public List<Student> getStudent() throws RemoteException { return list; } @Override public void addStudent(Student stu) throws RemoteException { Log.e(TAG, "setStudent: " ); list.add(stu); } }; @Nullable @Override public IBinder onBind(Intent intent) { Log.e(TAG, "onBind: " ); return mBinder; } }
并在manifest里面声明
<service android:name=".MyService"/>
第四步
客户端启动服务端
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private IMyAidlInterface sub; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { sub = IMyAidlInterface.Stub.asInterface(service); try { List<Student> list = sub.getStudent(); for(Student s : list){ Log.e(TAG, "onServiceConnected: "+s.getName()+" age:"+s.getAge()); } } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindService(new Intent(this,MyService.class),connection,BIND_AUTO_CREATE); } }
达到的初步结果就是
客户端可以跨进程拿到服务端的数据
可以测试一下
补充点
//manifest中: <service
android:name=".MyService" android:process=":another"> <intent-filter> <action android:name="com.ly.aidltest.MyService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service> //activity中: Intent intent = new Intent(); //5.0之后如果使用隐式启动service需要加上package,防止冲突,当然如果启动的是别的APP的service,要用目标的名字 intent.setPackage(getPackageName()); intent.setAction("com.ly.aidltest.MyService"); bindService(intent,connection,BIND_AUTO_CREATE);
- Service可以通过隐式启动
- 若客户端组件和服务分开在不同APP,必须要把该Parcelable实现类.java文件拷贝到客户端所在的APP,包路径要一致
本文地址:https://blog.csdn.net/u012346890/article/details/107787568