Android-服务跨进程通信(Binder/Messenger/AIDL)
来源:互联网 发布:淘宝买主机靠谱吗 编辑:程序博客网 时间:2024/06/05 15:32
官方文档中国版: https://developer.android.google.cn/guide/components/bound-services.html
谷歌2016年底为中国开发者提供中国版,方便访问!
绑定服务简介
Android服务与客户端相互调用(传递消息),必须创建绑定服务bindService()提供IBinder接口()!服务与客户端交互方式(传递消息)有三种:1.使用Binder类(客户端与服务在同一进程)如果服务与客户端在同一进程中运行,通过扩展Binder类并从onBind()返回它的一个实例来创建接口。客户端收到Binder后,可利用它直接访问Binder实现中乃至Service中可用的公共方法!2.使用Messenger(客户端与服务在不同进程,服务只能是单线程)不同进程工作,可用Messenger为服务创建接口。Message对象内含Handler。随后可与客户端分享一个IBinder,从而让客户端能利用 Message 对象向服务发送命令。此外,客户端还可定义自有 Messenger,以便服务回传消息!这是进程间通信(IPC)的最简单方法(AIDL的简化),因为Messenger会在服务单一线程创建所有请求队列。3.使用AIDL(客户端与服务在不同进程,服务可以是多线程)AIDL(Android 接口定义语言)执行所有将对象分解成原语的工作,操作系统可以识别这些原语并将它们编组到各进程中以执行IPC。之前的Messenger实际是以AIDL作为其底层结构。如果服务同时处理多个请求(多线程),应该用AIDL。注:大多数应用“都不会”使用AIDL来创建绑定服务,因为它可能要求具备多线程处理能力, 并可能导致实现的复杂性增加。因此,AIDL并不适合大多数应用!4.此外,还可用广播这个万金油组件进行传递消息,无论是不同进程,还是不同APP应用,都可用广播传递消息!但是需要注意的是, 广播有可能泄露数据、恶意程序发送广播等安全性问题,所以应该限制广播只在本应用内传播: 1.设置permission或Intent.setPackage,不把广播发送到应用外! 2.使用LocalBroadcastManager或设置android:exported="false"不接收应用外广播!
一.使用Binder类(客户端与服务在同一进程)
// 1.本地服务————————————————————————————————————public class LocalService extends Service { private final IBinder mLocalBinder = new LocalBinder(); public class LocalBinder extends Binder { LocalService getService() { return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return mLocalBinder; } public int getRandomNumber() { return new Random().nextInt(100); }}// 2.客户端————————————————————————————————————public class BindingActivity extends Activity { boolean mBound = false; @Override protected void onStart() { super.onStart(); // 绑定本地服务(同一进程) bindService(new Intent(this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { mBound = true; // 获取本地服务的实例,并调用方法,获取随机数 LocalService localService = ((LocalBinder) service).getService(); int num = localService.getRandomNumber(); } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; @Override protected void onStop() { super.onStop(); if (mBound) { // 解绑本地服务 unbindService(mConnection); mBound = false; } } }
二.使用Messenger(客户端与服务在不同进程,服务只能是单线程)
// 1.注册远程服务———————————————————————————————————— <service android:name=".MessengerService" android:process=":remote"> (process指定服务在另一个进程,名叫remote) </service>// 2.远程服务————————————————————————————————————public class MessengerService extends Service { final Messenger mServiceMessenger = new Messenger(new Handler(){ @Override public void handleMessage(Message msg) { // 接收客户端消息 switch (msg.what) { case 1: Toast.makeText(getApplicationContext(), "service hello!", Toast.LENGTH_SHORT).show(); Thread.sleep(3000); // 向客户端发消息 Messenger messenger = msg.replyTo; messenger.send(Message.obtain(null, 1, 0, 0)) break; } } }); @Override public IBinder onBind(Intent intent) { return mServiceMessenger.getBinder(); }}// 3.客户端————————————————————————————————————public class ActivityMessenger extends Activity { boolean mBound = false; private Messenger mActivityMessenger = new Messenger(new Handler(){ @Override public void handleMessage(Message msg){ // 接收远程服务消息 switch (msg.what){ case 1: Toast.makeText(ActivityMessenger.this, "activity hello!", Toast.LENGTH_SHORT).show(); break; } } }); private ServiceConnection mConnection = new ServiceConnection(){ public void onServiceConnected(ComponentName className, IBinder service) { mBound = true; // 向远程服务发消息 Messenger messenger = new Messenger(service); Message msg = Message.obtain(null, 1, 0, 0); msg.replyTo = mActivityMessenger messenger.send(msg); } public void onServiceDisconnected(ComponentName className) { mBound = false; } }; @Override protected void onStart() { super.onStart(); // 绑定远程服务(不同进程) bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // 解绑远程服务 if (mBound) { unbindService(mConnection); } }}
三.使用AIDL(客户端与服务在不同进程,服务可以是多线程)
1.创建AIDL接口
默认情况下AIDL支持下列数据类型int、long、char、boolean、String、CharSequence、List、MapList中元素都必须是以上类型、其他AIDL接口、可打包类型(即实现Parcelable接口).Map中元素都必须是以上类型、其他AIDL接口、可打包类型(即实现了Parcelable接口)不支持通用Map(如Map<String,Integer>形式的Map)// IRemoteService.aidl文件interface IRemoteService { // 注册回调 void registerCallback(IRemoteServiceCallBack cb); void unregisterCallback(IRemoteServiceCallBack cb); }// IRemoteServiceCallBack.aidl文件interface IRemoteServiceCallBack{ void valueChanged(int value);}
2.在远程服务中实现AIDL接口
public class RemoteService extends Service { // 一个服务会绑定多个客户端, 需要集合来存放客户端的回调接口 private RemoteCallbackList<IRemoteServiceCallBack> mCallbackList = new RemoteCallbackList<IRemoteServiceCallBack>(); // 实现IRemoteService.AIDL接口 private IRemoteService.Stub mBinder = new IRemoteService.Stub() { @Override public void registerCallback(IRemoteServiceCallBack cb)throws RemoteException { if (cb != null) { mCallbackList.register(cb); } } @Override public void unRegisterCallback(IRemoteServiceCallBack cb)throws RemoteException { if (cb != null) { mCallbackList.unregister(cb); } } }; // 通知所有客户端的回调接口 public void sendMsg(){ int N = mCallbackList.beginBroadcast(); for(int i=0;i<N;i++){ try { // 回调通知客户端 mCallbackList.getBroadcastItem(i).valueChanged(mValue); } catch (RemoteException e) { e.printStackTrace(); } } mCallbackList.finishBroadcast(); // 通知完成 } @Override public IBinder onBind(Intent intent) { return mBinder; }}
3.客户端
public class BindActivity extends Activity { IRemoteService mService = null; private boolean mIsBound = false; // 实现IRemoteServiceCallback.AIDL接口 private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() { /** * 来自远程服务的回调通知, * 此方法不在UI线程中, 更新UI需小心! */ public void valueChanged(int value) { ... } }; private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className,IBinder service){ mIsBound = true; mService = IRemoteService.Stub.asInterface(service); // 注册回调接口 mService.registerCallback(mCallback); } public void onServiceDisconnected(ComponentName className) { mIsBound = false; mService = null; } }; @Override protected void onStart() { super.onStart(); // 绑定远程服务 bindService(new Intent(BindActivity.this, RemoteService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); if (mIsBound){ // 取消回调接口 mService.unregisterCallback(mCallback); // 解绑远程服务 unbindService(mConnection); } }}
总结:
综上比较, AIDL实现客户端与远程服务通信太繁琐, 相互通知调用至少需要两个AIDL接口文件在远程服务中通知客户端, 需要循环通知, 相当繁琐!除非迫不得以(如服务可以是多线程运行), 实在不建议使用AIDL!客户端与服务在不同进程时, 建议服务单线程运行,使用Messenger通信, 这也是Android官方推荐的!
简书: http://www.jianshu.com/p/aec29a98bc1e
CSDN博客: http://blog.csdn.net/qq_32115439/article/details/72760479
GitHub博客:http://lioil.win/2017/05/25/Android_bindService.html
Coding博客:http://c.lioil.win/2017/05/25/Android_bindService.html
阅读全文
0 0
- Android-服务跨进程通信(Binder/Messenger/AIDL)
- 总结关于Service进程通信和跨进程通信的几种方式,AIDL,Messenger,Binder。
- AIDL与Messenger跨进程通信
- android 利用AIDL实现Binder跨进程通信
- Android 中的Binder跨进程通信机制与AIDL
- Android中的跨进程通信AIDL、Binder源码详解
- android Messenger 跨进程通信
- android Messenger 跨进程通信
- Android Messenger 跨进程通信!!!!!!!!!!!!!!!!!!
- Android Messenger 跨进程通信
- 【Android】Messenger 跨进程通信
- Android Messenger 跨进程通信
- Android Messenger 跨进程通信
- Android 跨进程通信--Messenger
- android Messenger跨进程通信
- Android 跨进程通信--Binder
- Android跨进程通信-AIDL
- Android跨进程通信-AIDL
- C/C++基础知识1
- 23种设计模式~工厂方法设计模式
- PHP命名空间详解
- react nativewindow环境的搭建
- 汇编语言: 试编写一段程序,要求在长度为 100H 字节的数组中,找出大于 61H 的无符号数的个 数并存入字节单元 UP 中,找出小于 2FH 的无符号数的个数并存入字节单元 DOWN 中。
- Android-服务跨进程通信(Binder/Messenger/AIDL)
- 转--【反病毒实验】WannaCry勒索病毒全解读,权威修复指南大集合
- PAT-A-1064. Complete Binary Search Tree (30)
- 在php中如何实现cookie即时生效,不用刷新就可以使用
- Java 如何使用radio button保存值
- 【lua】第一章-lua基础(搭建环境,变量语法基础)
- 汇编语言: 缓冲区
- zookeeper(zkCli)命令概览
- PHP中的超全局变量和魔术方法