在Android 中,一个进程通常无法访问另一个进程的内存。因此为了进程间通信,Android提供了AIDL机制,AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写,AIDL的作用是可以在自己的App里绑定一个其他App的Service,这样App可以通过AIDL与其他App进行交互。

App之间操作Service

这是BasicService应用中 AndroidManifest.xml定义的Service组件

                

MyService.java实现如下:

public class MyService extends Service {    private static final String TAG = "MyService";    private DownloadBinder mBinder = new DownloadBinder();    static class DownloadBinder extends Binder {        public void startDownload() {            // 模拟下载            Log.i(TAG, "startDownload executed");        }        public int getProgress() {            // 模拟返回下载进度            Log.i(TAG, "getProgress executed");            return 0;        }    }    public MyService() {    }    // 创建    @Override    public void onCreate() {        super.onCreate();        Log.i(TAG, "onCreate: ");    }    // 启动    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.i(TAG, "onStartCommand: ");        return super.onStartCommand(intent, flags, startId);    }    // 绑定    @Override    public IBinder onBind(Intent intent) {        Log.i(TAG, "onBind: ");        return mBinder;    }    // 解绑    @Override    public void unbindService(ServiceConnection conn) {        super.unbindService(conn);        Log.i(TAG, "unbindService: ");    }    // 销毁    @Override    public void onDestroy() {        super.onDestroy();        Log.i(TAG, "onDestroy: ");    }}

如何在另一个应用中远程对BasicService这个App中的应用进行操作呢?在AIDLDemo这个App中:

MainActivity.java如下:

public class MainActivity extends AppCompatActivity {    ServiceConnection connection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    public void aboutService(View view) {        int id = view.getId();        // Android5.0后不支持隐式启动了,最好都写成显示启动        Intent intent = new Intent();        intent.setAction("cn.tim.basic_service.myservice");        intent.setPackage("cn.tim.basic_service");        switch (id){            case R.id.start_btn:                startService(intent);                break;            case R.id.stop_btn:                stopService(intent);                break;            case R.id.bind_btn:                bindService(intent, connection, BIND_AUTO_CREATE);                break;            case R.id.unbind_btn:                unbindService(connection);                break;        }    }}

App之间Service通信

上面虽然完成了App之间的Service基本控制,比如启动、停止、绑定解绑等操作,但是即使绑定了Service,但是Activity还是并不知道服务到底去做了什么事情,以及完成得如何。这个时候就需要用到AIDL进行通信了。

首先需要明白的是要创建一套被调用的接口肯定要从被调用者出发,所以先在BasicService这个App中:

step1、创建AIDL文件,本例中命名为IMyAidlInterface.aidl:

step2、编辑AIDL文件,在这个AIDL文件里编写需要在服务绑定后通信的方法:

// IMyAidlInterface.aidlpackage cn.tim.basic_service;// Declare any non-default types here with import statementsinterface IMyAidlInterface {    // 定义自己需要的方法:获取当前服务的进度    int getProgress();}

step3、rebuild project自动生成对应的接口,接下来只要Rebuild一下工程就会在build > generated > aidl_source_output_dir > debug 下出现一个包,包下就是IMyAidlInterface.java:

其实Stub还会定义几个辅助方法,其中最值得注意的是 asInterface(),该方法会接收 IBinder(通常是传递给客户端 onServiceConnected() 回调方法的参数),并返回 Stub 接口的实例,其实就是通过代理的方式去完成IPC通信。

在MyService中绑定的回调函数onBind()中返回的那就是IMyAidlInterface.Stub代理对象了:

public class MyService extends Service {    ...        @Override    public IBinder onBind(Intent intent) {        Log.i(TAG, "onBind: ");        //return mBinder;        return new IMyAidlInterface.Stub() {            @Override            public int getProgress() {                Log.i(TAG, "getProgress: IMyAidlInterface");                return 0;            }        };    }}

这样即使是在BasicService这个App中也可以使用IMyAidlInterface中的代理对象:

ServiceConnection connection = new ServiceConnection() {    @Override    public void onServiceConnected(ComponentName name, IBinder service) {        // MyService.DownloadBinder binder = (MyService.DownloadBinder) service;        // binder.startDownload();        // binder.getProgress();        IMyAidlInterface asInterface = IMyAidlInterface.Stub.asInterface(service);        try {            asInterface.getProgress();        } catch (RemoteException e) {            e.printStackTrace();        }    }    @Override    public void onServiceDisconnected(ComponentName name) {    }};

step4、复制同样的AIDL文件到AIDLDemo这个工程中,AIDL作为调用者。需要注意的是必须放到相同的包下,因此需要手动建包,再把文件复制过来:

同样的方式,工程进行一次rebuild,同样会生成IMyAidlInterface.java,这样大家都具有了IMyAidlInterface这个接口,使用起来也就还是一样了,MainActivity.java:

step5、在AIDLDemo这个工程中使用IMyAidlInterface

public class MainActivity extends AppCompatActivity {    private static final String TAG = "AIDLMainActivity";    ServiceConnection connection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            IMyAidlInterface asInterface = IMyAidlInterface.Stub.asInterface(service);            try {                int progress = asInterface.getProgress();                Log.i(TAG, "onServiceConnected: progress = " + progress);            } 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);    }    public void aboutService(View view) {        int id = view.getId();        Intent intent = new Intent();        intent.setAction("cn.tim.basic_service.myservice");        intent.setPackage("cn.tim.basic_service");        switch (id){            case R.id.start_btn:                startService(intent);                break;            case R.id.stop_btn:                stopService(intent);                break;            case R.id.bind_btn:                bindService(intent, connection, BIND_AUTO_CREATE);                break;            case R.id.unbind_btn:                unbindService(connection);                break;        }    }}

可以看到,AIDLDemo这个App的MainActivity已经和BasicService这个App的MyService服务已经绑定了,并且可以正常的调用MyService中的方法。至此,通过AIDL实现的远程绑定服务通信已经完成了:

tips:上面logcat同时打印两个TAG的日志的方法就是在配置过滤器LogTag:MyService | AIDLMainActivity即可。

使用AIDL的注意事项

1、只有在需要不同应用的客户端通过 IPC 方式访问服务,并且希望在服务中进行多线程处理时,才有必要使用 AIDL。如果无需跨不同应用执行并发 IPC,则应通过实现 Binder 来创建接口;或者如果想执行 IPC,但不需要处理多线程,推荐使用 Messenger 来实现接口。

2、如果需要在首次发布 AIDL 接口后对其进行更改,则每次更改必须保持向后兼容性,以免中断其他应用使用对应的服务。换言之,由于只有在将 .aidl 文件复制到其他应用后,才能使其访问服务接口,因而必须保留对原始接口的支持。

原文地址:《远程服务使用AIDL通信》

更多相关文章

  1. Android(安卓)官方示例:android-architecture 学习笔记(二)之todo
  2. 远程服务使用AIDL通信
  3. android 进程间通信示例
  4. Android(安卓)技术专题系列之十七 -- volume 服务
  5. Android(安卓)添加系统服务
  6. android、ios与服务器端php使用rsa加密解密通讯
  7. Android中如何使用Intent在Activity之间传递对象[使用Serializab
  8. Android中的Data Binding初探 (三)
  9. android gradle plugin 1.3.0 以上使用 public.xml 固定 id

随机推荐

  1. Android获取所在地城市名
  2. Android:实现一种浮动选择菜单的效果
  3. Android中自定义数据适配器Adapter
  4. Android Studio开发Android wear环境搭建
  5. Google Android官方文档进程与线程(Proce
  6. Android adb devices显示no permission
  7. android-XML解析Dom,Sax,Pull
  8. android 手机信息获得
  9. java.net.UnknownServiceException: CLEA
  10. android获取控件宽和高