需求
项目需要,将做好的项目作为一个服务提供给另一个公司。我们需要提供一个apk,所以设计到进程间交互,不得不了解一下AIDL了。
了解一下AIDL
之前准备面试的时候,或多或少的了解了一点AIDL,不过现在忘记得差不多了。
所以网上随便找了几篇不错的文章。
1.进程通信之AIDL的使用。
2.学习AIDL,这一篇就够了。
一个简单的demo
自己搞了一个简单的demo。
实现了进程间通信,可以传输普通类型和实体类型。
首先是服务端。
1.第一个aidl接口。
// IMyAidlInterface.aidl package com.xf.test1;import com.xf.test1.IAidlCallBack; import com.xf.test1.Entity; // Declare any non-default types here with import statementsinterface 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);String getStr(String str);int getPid();Entity getEntity();Entity setEntity(in Entity entity);void registerCallBack(IAidlCallBack callback);void unregisterCallBack(IAidlCallBack callback); }
2.第二个aidl接口。
// IAidlCallBack.aidl package com.xf.test1;import com.xf.test1.Entity;// Declare any non-default types here with import statementsinterface IAidlCallBack {void callBack(String name);void callBackEntity(in Entity entity); }
3.第三个aidl接口。
// Person.aidl package com.xf.test1;parcelable Entity;
4.封装的一个IBinder。
package com.xf.test1;import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable;public class AIDLService extends Service {private AIDLImp mBinder;@Overridepublic void onCreate() {super.onCreate();mBinder = new AIDLImp(this);}@Nullable@Overridepublic IBinder onBind(Intent intent) {return mBinder;}@Overridepublic void onDestroy() {super.onDestroy();mBinder.KillAll();} }
5.AIDL服务。
package com.xf.test1;import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable;public class AIDLService extends Service {private AIDLImp mBinder;@Overridepublic void onCreate() {super.onCreate();mBinder = new AIDLImp(this);}@Nullable@Overridepublic IBinder onBind(Intent intent) {return mBinder;}@Overridepublic void onDestroy() {super.onDestroy();mBinder.KillAll();} }
6.实体类型。
package com.xf.test1;import android.os.Parcel; import android.os.Parcelable;/*** Description: 简单实体类** @version V1.0.0* Createdate: 2018/6/22* @author: wja 1211241203@qq.com*/ public class Entity implements Parcelable {private String name;private int parameter1;private double parameter2;public Entity(String name){this.name=name;}public Entity(String name, int parameter1, double parameter2) {this.name = name;this.parameter1 = parameter1;this.parameter2 = parameter2;}public int getParameter1() {return parameter1;}public void setParameter1(int parameter1) {this.parameter1 = parameter1;}public double getParameter2() {return parameter2;}public void setParameter2(double parameter2) {this.parameter2 = parameter2;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(this.name);dest.writeInt(this.parameter1);dest.writeDouble(this.parameter2);}protected Entity(Parcel in) {this.name = in.readString();this.parameter1 = in.readInt();this.parameter2 = in.readDouble();}public static final Creator<Entity> CREATOR = new Creator<Entity>() {@Overridepublic Entity createFromParcel(Parcel source) {return new Entity(source);}@Overridepublic Entity[] newArray(int size) {return new Entity[size];}};@Overridepublic String toString() {return "Entity{" +"name='" + name + '\'' +", parameter1=" + parameter1 +", parameter2=" + parameter2 +'}';} }
7.清单文件。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.xf.test1"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><!--<intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /><data android:scheme="com.xf.aidl.test" /></intent-filter>--></activity><service android:name=".AIDLService"><intent-filter><action android:name="com.xf.aidl" /><category android:name="android.intent.category.DEFAULT" /><!--<action android:name="android.intent.action.MAIN" />--><!--<category android:name="android.intent.category.LAUNCHER" />--></intent-filter></service></application></manifest>
8.服务端如何运行(不使用启动图标的方式)
然后点击进去
9.最后点击运行,服务就安装在手机啦。
其次,是客户端。
1.客户端的aidl文件和服务端的完全一样。(当然路径可以不一样,为了方便我直接copy的,路径不一样也是可以的,测试过的)
2.然后注意实体类型所在的包一定要和服务端的一致,负责找不到这个实体的。
3.最后是客户端的主页面。
package com.xf.test2;import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View;import com.xf.test1.Entity; import com.xf.test1.IAidlCallBack; import com.xf.test1.IMyAidlInterface;import java.util.Random;public class MainActivity extends AppCompatActivity {private IMyAidlInterface mIMyAidlInterfaceService;private ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mIMyAidlInterfaceService = IMyAidlInterface.Stub.asInterface(service);try {mIMyAidlInterfaceService.registerCallBack(mIAidlCallBack);} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {try {mIMyAidlInterfaceService.unregisterCallBack(mIAidlCallBack);} catch (RemoteException e) {e.printStackTrace();}mIMyAidlInterfaceService = null;}};private IAidlCallBack mIAidlCallBack = new IAidlCallBack.Stub() {@Overridepublic void callBack(String name) throws RemoteException {Log.e("info---->","服务端给我发消息啦:"+name);ToastUtil.showShort(MainActivity.this,"服务端给我发消息啦:"+name);}@Overridepublic void callBackEntity(Entity entity) {Log.e("info---->","服务端给我发实体消息啦:"+entity.toString());ToastUtil.showShort(MainActivity.this,"服务端给我发实体消息啦:"+entity.toString());}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overrideprotected void onDestroy() {super.onDestroy();if (mServiceConnection != null)unbindService(mServiceConnection);}/*** 绑定服务* @param view*/public void doClick(View view) {Intent intent = new Intent();intent.setAction("com.xf.aidl");intent.setPackage("com.xf.test1");bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);}/*** 获取服务器发送过来的消息* @param v*/public void doAction(View v) {if (mIMyAidlInterfaceService != null) {try {String newstr = mIMyAidlInterfaceService.getStr("Hello world");int pid = mIMyAidlInterfaceService.getPid();Log.e("info---->", newstr + " pid:" + pid);} catch (RemoteException e) {e.printStackTrace();}}}/*** 客户端自己设置实体,发送给服务端* 通过随机数设置实体参数* @param v*/public void doActionSetEntity(View v){if (mIMyAidlInterfaceService != null) {try {Random random=new Random();mIMyAidlInterfaceService.setEntity(new Entity("客户端",random.nextInt(100),random.nextDouble()));} catch (RemoteException e) {e.printStackTrace();}}} }
下面是布局文件。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><RelativeLayoutandroid:layout_marginTop="100dp"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_width="300dp"android:layout_height="wrap_content"android:onClick="doClick"android:text="绑定服务"android:layout_centerInParent="true"/></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_width="300dp"android:layout_height="wrap_content"android:onClick="doAction"android:text="获取消息"android:layout_centerInParent="true"/></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:layout_width="300dp"android:layout_height="wrap_content"android:onClick="doActionSetEntity"android:text="客户端设置实体"android:layout_centerInParent="true"/></RelativeLayout></LinearLayout>
运行效果是这样的:
这里客户端首先需要绑定服务
点击了获取消息:直接获取服务端创建好的实体类。
点击了客户端设置实体:通过产生随机数,客户端调用aidl接口设置实体。
如果再次点击获取消息:在服务端进行判断,如果客户端设置过实体,就把该实体发送回客户端。
demo地址:https://github.com/JasonToJan/AIDLDemo
个人小结
1.首先要理解aidl是干什么的:进程间交互。不同apk实现通信。
2.为什么可以做到进程间通信了,谁给两个进程之间搭起了一座桥梁呢?AIDL,其实就是一个接口,实现进程之间对接的功能。
3.两个进程要做到通信,aidl一定要保证一致,不然就是牛头不对马嘴了。
4.aidl如何实现数据传输了,binder。所以demo就把binder直接封装起来,基本所有逻辑都在这个封装类中进行即可。
5.再深入底层,binder是如何实现数据传输的呢?这就涉及到操作系统的知识了,binder处于一个内存共享区域,可以实现进程间通信。