aidl

目录

  • 前言
  • 案例
    • aidl支持传递的数据类型
    • 服务apk
    • 客户apk

前言

  aidl 是 android interface definition language 的英文缩写,意思 Android 接口定义语言

  使用 aidl 可以帮助我们发布以及调用远程服务,实现跨进程通信

  将服务的 aidl 放到对应的 src 目录然后build,工程的 gen 目录会生成相应的接口类
  通过 bindService(Intent service, ServiceConnection conn, int flags) 方法绑定远程服务,在bindService 中有一个 ServiceConnec 接口,我们需要覆写该类的 onServiceConnected(ComponentName, IBinder)方法,这个方法的第二个参数 IBinder 对象其实就是已经在 aidl 中定义的接口,因此我们可以将 IBinder 对象强制转换为 aidl 中的接口类
  通过 IBinder 获取到的对象(也就是 aidl 文件生成的接口)其实是系统产生的代理对象,该代理对象既可以跟我们的进程通信,又可以跟远程进程通信,作为一个中间的角色实现了进程间通信

案例

该案例包含回调接口使用及对象的传递,参考后基本能操作所有常规的需求
其中回调通过使用高德定位服务提供参考,对象传递通过简单的方法提供参考

服务和客户apk的gradle中均需包含aidl目录下的代码

sourceSets {
    main {
        java.srcDirs = ['src/main/java', 'src/main/aidl']
    }
}

aidl支持传递的数据类型

  1. byte、int、long、float、double、char、boolean,不支持short

  2. String、CharSequence

  3. List(接收端必须为ArrayList)、Map(接收端必须为HashMap)

  4. Parcelable(需import)

  5. 其他已定义的aidl接口(需import)

服务apk

  • 封装好的高德定位能力

    import com.amap.api.location.AMapLocation;
    import com.amap.api.location.AMapLocationClient;
    import com.amap.api.location.AMapLocationClientOption;
    import com.amap.api.location.AMapLocationListener;
    import com.amap.api.services.core.PoiItem;
    import com.amap.api.services.poisearch.PoiResult;
    import com.amap.api.services.poisearch.PoiSearch;
    import cc.catface.services.App;
    
    public class AmapEngine implements AMapLocationListener, PoiSearch.OnPoiSearchListener {
    
    
        /** 初始化定位 */
        private AMapLocationClient locationClient = null;
        private AMapLocationClientOption locationOption = null;
    
    
        /** 默认的定位参数 */
        private AMapLocationClientOption mOption;
    
        private AMapLocationClientOption getDefaultOption() {
            mOption = new AMapLocationClientOption();
            mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
            mOption.setGpsFirst(true);
            mOption.setHttpTimeOut(30000);
            mOption.setInterval(mContinuedLocationInterval);
            mOption.setNeedAddress(true);
            mOption.setOnceLocation(true);
            mOption.setOnceLocationLatest(false);
            AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);
            mOption.setSensorEnable(false);
            mOption.setWifiScan(true);
            mOption.setLocationCacheEnable(true);
            mOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.DEFAULT);
            return mOption;
        }
    
        private int mContinuedLocationInterval = 2_000;
    
        /** 设置持续定位的时间间隔 */
        @Deprecated public void setContinuedLocationInterval(int interval) {
            mContinuedLocationInterval = interval;
        }
    
    
        /** 供aidl使用的定位和位置列表搜索的回调 */
        private LocationCallback mLocationCallback;
    
        public void setLocationCallback(LocationCallback locationCallback) {
            this.mLocationCallback = locationCallback;
        }
    
    
        public interface LocationCallback {
            void onLocation(long timestamp, AMapLocation location);
    
            void onError(int code, String info, String detail);
        }
    
        private PoiSearchCallback mPoiSearchCallback;
    
        public void setPoiSearchCallback(PoiSearchCallback poiSearchCallback) {
            this.mPoiSearchCallback = poiSearchCallback;
        }
    
        public interface PoiSearchCallback {
            void onResult(PoiResult result);
        }
    
    
        /* 开始定位 */
        public void startLocation() {
            locationClient = new AMapLocationClient(App.getInstance());
            locationOption = getDefaultOption();
            locationClient.setLocationOption(locationOption);
            locationClient.setLocationListener(this);
            locationClient.startLocation();
        }
    
        @Override public void onLocationChanged(AMapLocation location) {
            if (null == mLocationCallback) return;
            if (null == location) {
                mLocationCallback.onError(-0x99, "null == location", "null == location");
                return;
            }
    
            int code = location.getErrorCode();
            if (0 != code) {
                mLocationCallback.onError(code, location.getErrorInfo(), location.getLocationDetail());
                return;
            }
    
            mLocationCallback.onLocation(System.currentTimeMillis(), location);
        }
    
        /* 停止定位 */
        public void stopLocation() {
            if (null != locationClient) {
                locationClient.stopLocation();
            }
        }
    
    
        /* 搜索位置列表 */
        public void startPoi(String poi, int pageNum) {
            startPoi(poi, 20, pageNum);
        }
    
        public void startPoi(String poi, int pageSize, int pageNum) {
            PoiSearch.Query query = new PoiSearch.Query(poi, "", "");
            query.setPageSize(pageSize);  // 每页多少条结果
            query.setPageNum(pageNum);    // 查询页码
            PoiSearch search = new PoiSearch(App.getInstance(), query);
            // search.setBound(new PoiSearch.SearchBound(new LatLonPoint(location.getLatitude(), location.getLongitude()), 10000));
            search.setOnPoiSearchListener(this);
            search.searchPOIAsyn();
        }
    
        @Override public void onPoiSearched(PoiResult poiResult, int i) {
            if (null == mPoiSearchCallback) return;
            mPoiSearchCallback.onResult(poiResult);
        }
    
        @Override public void onPoiItemSearched(PoiItem poiItem, int i) { }
    
    
        /** 退出定位功能,在activity/fragment退出时调用 */
        public void release() {
            stopLocation();
            if (null != locationClient) locationClient.unRegisterLocationListener(this);
            if (null != mLocationCallback) mLocationCallback = null;
            if (null != mPoiSearchCallback) mPoiSearchCallback = null;
        }
    }
    
  • aidl文件

    1. 回调接口

      // 定位结果回调
      package cc.catface.services;
      interface LocationCallback {
          void onLocation(long timestamp, String locationJson);
      
          void onError(int code, String info, String detail);
      }
      

      // 位置列表结果回调
      package cc.catface.services;
      interface PoiSearchCallback {
      
          void onResult(inout List<String> poiList);
      
      }
      
    2. 对象Person类

      package cc.catface.services;
      import android.os.Parcel;
      import android.os.Parcelable;
      
      public class Person implements Parcelable {
      
          private int age;
          private String name;
      
          public Person() {
          }
      
          public Person(int age, String name) {
              this.age = age;
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          @Override public int describeContents() {
              return 0;
          }
      
          /** write和read顺序需对应 */
          @Override public void writeToParcel(Parcel dest, int flags) {
              dest.writeInt(age);
              dest.writeString(name);
          }
      
          public void readFromParcel(Parcel source) {
              age = source.readInt();
              name = source.readString();
          }
      
          protected Person(Parcel in) {
              age = in.readInt();
              name = in.readString();
          }
      
          public static final Creator<Person> CREATOR = new Creator<Person>() {
              @Override public Person createFromParcel(Parcel source) {
                  return new Person(source);
              }
      
              @Override public Person[] newArray(int size) {
                  return new Person[size];
              }
          };
      }
      

      // 对象类对应的aidl文件
      package cc.catface.services;
      parcelable Person;
      
    3. 将要被实例化使用的代理类

      package cc.catface.services;
      import cc.catface.services.LocationCallback;
      import cc.catface.services.PoiSearchCallback;
      
      import cc.catface.services.Person;
      
      interface IAmap {
      
      	/** 通过回调使用定位服务供参考 */
          void setLocationCallback(LocationCallback locationCallback);
      
          void setPoiSearchCallback(PoiSearchCallback poiSearchCallback);
      
          void startLocation();
      
          void stopLocation();
      
          void startPoi(String poi, int pageSize, int pageNum);
      
          void releaseEngine();
      
      
          /** 传递对象的操作方法供参考 */
          String inPersonInfo(in Person person);
      
          String outPersonInfo(out Person person);
      
          String inOutPersonInfo(inout Person person);
      }
      

      in:参数由客户端设置
      out:参数由服务端设置
      inout:参数由客户端和服务端设置都可

      传递的对象参数前必须声明in/out/inout其中的一种,最好按实际情况设置,不然全部设置成inout虽然也可以,但是会增加系统负担,白给

    • 服务

      public class AmapService extends Service {
      
          private AmapEngine mEngine;
          private LocationCallback mLocationCallback;
          private PoiSearchCallback mPoiSearchCallback;
      
          public class Binder extends IAmap.Stub {
      
              public Binder() {
                  if (null == mEngine) {
                      mEngine = new AmapEngine();
                  }
                  
                  registerEngineCallbacks();  // 将amap服务的回调添加进aidl的回调内
              }
      
              /** 注册定位回调 */
              @Override public void setLocationCallback(LocationCallback locationCallback) throws RemoteException {
                  mLocationCallback = locationCallback;
              }
      
              /** 注册位置列表回调 */
              @Override public void setPoiSearchCallback(PoiSearchCallback poiSearchCallback) throws RemoteException {
                  mPoiSearchCallback = poiSearchCallback;
              }
      
      
              /** 开始定位 */
              @Override public void startLocation() throws RemoteException {
                  if (null == mEngine) return;
                  mEngine.startLocation();
              }
      
              /** 暂停定位 */
              @Override public void stopLocation() throws RemoteException {
                  if (null == mEngine) return;
                  mEngine.stopLocation();
              }
      		
      		/** 开始搜索位置列表 */
              @Override public void startPoi(String poi, int pageSize, int pageNum) throws RemoteException {
                  if (null != mEngine) {
                      mEngine.startPoi(poi, pageSize, pageNum);
                  }
              }
      
              /** 释放定位 */
              @Override public void releaseEngine() throws RemoteException {
                  if (null == mEngine) return;
                  mEngine.release();
              }
      
      
              @Override public String inPersonInfo(Person person) throws RemoteException {
                  return person.getAge() + " || " + person.getName() + " || in";
              }
      
              @Override public String outPersonInfo(Person person) throws RemoteException {
                  return person.getAge() + " || " + person.getName() + " || out";
              }
      
              @Override public String inOutPersonInfo(Person person) throws RemoteException {
                  return person.getAge() + " || " + person.getName() + " || in&out";
              }
          }
      
          @Nullable @Override public IBinder onBind(Intent intent) {
              return new AmapService.Binder();
          }
      
      
          private void registerEngineCallbacks() {
              mEngine.setLocationCallback(new AmapEngine.LocationCallback() {
                  @Override public void onLocation(long timestamp, AMapLocation location) {
                      if (null == mLocationCallback) return;
                      try {
                          mLocationCallback.onLocation(timestamp, location.toStr());
                      } catch (RemoteException e) {
                          e.printStackTrace();
                      }
                  }
      
                  @Override public void onError(int code, String info, String detail) {
                      try {
                          mLocationCallback.onError(code, info, detail);
                      } catch (RemoteException e) {
                          e.printStackTrace();
                      }
                  }
              });
              mEngine.setPoiSearchCallback(new AmapEngine.PoiSearchCallback() {
                  @Override public void onResult(PoiResult result) {
                      if (null == mPoiSearchCallback) return;
      
                      try {
                          List<String> poiList = new ArrayList<>();
                          ArrayList<PoiItem> pois = result.getPois();
                          for (PoiItem poi : pois) {
                              String snippet = poi.getSnippet();
                              if (!TextUtils.isEmpty(snippet)) {  // 过滤可能为空串的位置条目
                                  poiList.add(poi.getSnippet());
                              }
                          }
      
                          mPoiSearchCallback.onResult(poiList);
                      } catch (RemoteException e) {
                          e.printStackTrace();
                      }
                  }
              });
          }
      }
      
    • 清单文件声明服务

      <service
      android:name="cc.catface.services.amap.AmapService"
          android:enabled="true"
          android:exported="true"
          android:process=":remote">
          <intent-filter>
              <action android:name="cc.catface.services.action"/>
              <category android:name="android.intent.category.DEFAULT"/>
          intent-filter>
      service>
      

      android:enabled:是否可被系统实例化,默认true

      android:exported:是否可被三方应用隐式调用,如配置了intent-filter则默认true若未配置则默认false;若置为false则即使配了intent-filter也无法被三方应用隐式调用

      android:process:值为:remote代表该服务在单独的进程中运行,且该进程名前附加当前包名如cc.catface.services:remote;若值为remote则该进程名为remote,无附加包名

客户apk

  • 使用参考

    public class AmapAIDLActivity extends Activity {
    
        protected IAmap mService;
        ServiceConnection mServiceConnection;
    
        @Override protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_amap_aidl_client);
    
            findViewById(R.id.btFinish).setOnClickListener(v -> finish());
    
            findViewById(R.id.btStart).setOnClickListener(v -> {
                try {
                    mService.startLocation();
    
    				// 对象传递使用参考
                    String p1 = mService.inPersonInfo(new Person(17, "alistar"));
                    String p2= mService.outPersonInfo(new Person(28, "ashe"));
                    String p3= mService.inOutPersonInfo(new Person(39, "akali"));
                    Log.d("persons-->", p1+ "\n" + p2 + "\n" + p3);
                    
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            });
    
            findViewById(R.id.btStop).setOnClickListener(v -> {
                try {
                    mService.stopLocation();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            });
    
            findViewById(R.id.btPoi).setOnClickListener(v -> {
                String poi = ((EditText) findViewById(R.id.etPoi)).getText().toString().trim();
                String page = ((EditText) findViewById(R.id.etPoiPage)).getText().toString().trim();
                try {
                    mService.startPoi(poi, 20, Integer.valueOf(page));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            });
    
            findViewById(R.id.btRelease).setOnClickListener(v -> {
                try {
                    mService.releaseEngine();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            });
    
            initCallbacks();
            initConnection();
            bindService();
        }
    
        void bindService() {
            if (mService == null) {
                Intent intent = new Intent();
                intent.setPackage("cc.catface.services");
                intent.setAction("cc.catface.services.action");
                bindService(intent, mServiceConnection, Service.BIND_AUTO_CREATE);
            }
        }
    
        private LocationCallback.Stub mLocationCallback;
        private PoiSearchCallback.Stub mPoiSearchCallback;
    
        private void initCallbacks() {
            mLocationCallback = new LocationCallback.Stub() {
                @Override public void onLocation(long timestamp, String locationJson) throws RemoteException {
                    Log.d("catface", "onLocation: " + timestamp + " || " + locationJson);
                }
    
                @Override public void onError(int code, String info, String detail) throws RemoteException {
    
                }
            };
            mPoiSearchCallback = new PoiSearchCallback.Stub() {
                @Override public void onResult(List<String> poiList) throws RemoteException {
                    for (String poi : poiList) {
                        Log.d("catface", "onResult: " + poi);
                    }
                }
            };
        }
    
    
        private void initConnection() {
            mServiceConnection = new ServiceConnection() {
    
                @Override public void onServiceDisconnected(ComponentName name) {
                    Log.d("catface", "服务断开连接");
                }
    
                @Override public void onServiceConnected(ComponentName name, IBinder service) {
                    mService = IAmap.Stub.asInterface(service);
                    Log.d("catface", "服务已连接 || service is: " + mService + " || mLocationCallback: " + mLocationCallback + " || mPoiSearchCallback: " + mPoiSearchCallback);
                    try {
                        mService.setLocationCallback(mLocationCallback);
                        mService.setPoiSearchCallback(mPoiSearchCallback);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            };
        }
    }
    

    // 对象传递打印
    17 || alistar || in
    0 || null || out	// 因为是out,所以接收不到客户端设置的值,合理
    39 || akali || in&out
    

你可能感兴趣的:(android_基础知识)