1、使用Messenger

 Messenger可以翻译为信使,通过它可以在不同进程中传递messenge对象,在messenge中放入我们需要传递的数据,就可以轻松实现数据在进程中传递。

 服务段进程:

  需要在服务端创建一个Service来处理客户端的连接需求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可。

  如果需要回复给客户端消息,可以通过Messange的replyTo参数创建一个Messenger,然后再创建一个想要传递的messenge,再然后使用Messenger传递这个messenge

  1. public class MyService extends Service {
  2. private static final String TAG = "MessengerService";
  3.  
  4. private static class MessengerHandler extends Handler{
  5. @Override
  6. public void handleMessage(Message msg) {
  7. switch (msg.what){
  8. case 0:
                //打印接收到的Message对象的内容
  9. Log.i(TAG,"receive msg form Client:" + msg.getData().getString("msg"));
                
                //使用接收到的messenge对象的replyTo参数创建Messenger进行回复
  10. Messenger client = msg.replyTo;
  11. Message replyMessage = Message.obtain(null,1);
  12. Bundle bundle = new Bundle();
  13. bundle.putString("reply","已收到消息");
  14. replyMessage.setData(bundle);
  15. try{
  16. client.send(replyMessage);
  17. }catch (RemoteException e){
  18. e.printStackTrace();
  19. }
  20. break;
  21. default:
  22. super.handleMessage(msg);
  23.  
  24. }
  25. }
  26. }
  27. private final Messenger mMessenger = new Messenger(new MessengerHandler());
  28.  
  29. @Nullable
  30. @Override
  31. public IBinder onBind(Intent intent) {
  32. return mMessenger.getBinder();
  33. }
  34. }

  客户端进程:

    先绑定服务端的Service,绑定成功后使用服务端返回的使用服务端返回的IBinder创建Messenger并使用其发送消息。

    如果想要接受服务端的回复同样需要创建一个Handler并创建新的Messenger,并把这个Messenger通过replyTo传递给服务端

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. private static final String TAG = "MessengerService";
  4.  
  5. //服务端传来的Messenger
  6. private Messenger mService;
  7.  
  8. //客户端的Messnger
  9. private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
  10.  
  11. private static class MessengerHandler extends Handler{
  12. @Override
  13. public void handleMessage(Message msg) {
  14. switch (msg.what){
  15. case 1:
  16. //打印服务端返回的消息
  17. Log.i(TAG, "receive msg from Service:" + msg.getData().getString("reply"));
  18. break;
  19. default:
  20. super.handleMessage(msg);
  21. }
  22. }
  23. }
  24. private ServiceConnection mConnection = new ServiceConnection() {
  25. @Override
  26. public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
  27.  
  28. //使用服务端返回的IBinder创建Messenger并使用其发送消息
  29. mService = new Messenger(iBinder);
  30. Message msg = Message.obtain(null,0);
  31. Bundle data = new Bundle();
  32. data.putString("msg","hello this is client");
  33. msg.setData(data);
  34.  
  35. //将客户端的Messenger通过replyTo传递给服务端
  36. msg.replyTo = mGetReplyMessenger;
  37.  
  38. try{
  39. mService.send(msg);
  40. }catch (RemoteException e){
  41. e.printStackTrace();
  42. }
  43. }
  44.  
  45. @Override
  46. public void onServiceDisconnected(ComponentName componentName) {
  47.  
  48. }
  49. };
  50. @Override
  51. protected void onCreate(Bundle savedInstanceState) {
  52. super.onCreate(savedInstanceState);
  53. setContentView(R.layout.activity_main);
  54. Intent intent = new Intent(this,MyService.class);
  55. //绑定Service
  56. bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
  57. }
  58.  
  59. @Override
  60. protected void onDestroy() {
  61. unbindService(mConnection);
  62. super.onDestroy();
  63. }
  64. }

2、使用AIDL

  上面的Messenger是以串行的方式处理客户端发来的消息,如果大量的消息同时发送到服务端,服务端仍然只能一个一个的处理,这种就可以使用AIDL

  首先是创建AIDL接口(Book类,Book.aidl,IBookManager.aidl 具体代码可以看IPC机制1

    在AIDL文件中,并不是所有的数据类型都是可以使用的,支持的类型有:

    • 基本类型(int、long、char、boolean等)
    •   List:只支持ArrayList,且每个元素都必须被AIDL支持
    • Map:只支持HashMap,且每个元素都必须被AIDL支持,包括key和value;
    • Parcelable:所有实现了Parcelable接口的对象
    •   AIDL:所有的AIDL接口本身也可以在AIDL中使用,

    以上为AIDL所支持的所有类型,其中现了Parcelable接口的对象和AIDL对象必须显式的important进来,不管它们是否与当前文件位于同一包内。

    如果AIDL文件用到 了自定义的Parcelable对象,就必须新建一个和它同名的AIDL文件,并在其中声明它为Parcelable类型。

    还要注意的是,AIDL中除了基本数据类型,其他类型的参数必须标上方向:in、out或者inout,in表示输入型参数,out表示输出型参数,inout表示输入输出型参数。

    最后,AIDL接口中只支持方法,不支持声明静态变量。

  然后是远程服务端的Service的实现:

    上面只是定义了接口,现在就需要实现这个接口:

  1. public class BookManagerService extends Service {
  2.  
  3. private static final String TAG = "BMS";
  4.  
  5. private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
  6.  
  7. private Binder mBinder = new IBookManager.Stub() {
  8. @Override
  9. public List<Book> getBookList() throws RemoteException {
  10. return mBookList;
  11. }
  12.  
  13. @Override
  14. public void addBook(Book book) throws RemoteException {
  15. mBookList.add(book);
  16. }
  17.  
  18. };
  19.  
  20. @Override
  21. public void onCreate() {
  22. super.onCreate();
  23. mBookList.add(new Book(1,"Android"));
  24. mBookList.add(new Book(2,"ios"));
  25. }
  26.  
  27. @Override
  28. public IBinder onBind(Intent intent) {
  29. return mBinder;
  30. }
  31. }

  这里采用了CopyOnWriteArrayList,这是因为CopyOnWriteArrayList支持并发读写,类似的还有ConcurrentHashMap,这是因为AIDL方法是在服务端的Binder线程池中执行的,因此当多个客户端同步连接的时候,会出现多线程同时访问的情形。

  再然后就是客户端的实现:

  1. public class BookManagerActivity extends AppCompatActivity {
  2.  
  3. private static final String TAG = "BMS";private ServiceConnection mConnection = new ServiceConnection() {
  4. @Override
  5. public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
  6. IBookManager bookManager = IBookManager.Stub.asInterface(iBinder);
  7. try {
  8. List<Book> list = bookManager.getBookList();
  9. Log.i(TAG,"query book list, list type:" + list.getClass().getCanonicalName());
  10. for (Book book:list) {
  11. Log.i(TAG, "query book list: [book id:" + book.bookId + " bookName:" + book.bookName + "]");
  12. }
  13. }catch (RemoteException e){
  14. e.printStackTrace();
  15. }
  16. }
  17.  
  18. @Override
  19. public void onServiceDisconnected(ComponentName componentName) {
  20. }
  21. };
  22.  
  23. @Override
  24. protected void onCreate(Bundle savedInstanceState) {
  25. super.onCreate(savedInstanceState);
  26. setContentView(R.layout.activity_book_manager);
  27. Intent intent = new Intent(this, BookManagerService.class);
  28. bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
  29. }
  30.  
  31. @Override
  32. protected void onDestroy() {
  33. unbindService(mConnection);
  34. super.onDestroy();
  35. }
  36. }

  Log输出如下:

  1. 12-07 14:48:48.516 9198-9198/com.example.administrator.test I/BMS: query book list, list type:java.util.ArrayList
  2. 12-07 14:48:48.516 9198-9198/com.example.administrator.test I/BMS: query book list: [book id:1 bookName:Android]
  3. 12-07 14:48:48.516 9198-9198/com.example.administrator.test I/BMS: query book list: [book id:2 bookName:ios]

  可以发现,虽然我们在服务端返回的是CopyOnWriteArrayList,但是客户端收到的却是ArrayList.这是因为AIDL中支持的是抽象的List,而List只是一个接口,在Binder中是按照List的规范去访问数据,并最终返回ArrayList给客户端。

3、使用ContentProvider

  ContentProvider是Android中提供的专门用于不同应用间进行数据共享的方式。不过ContentProvider的底层实现同样也是Binder。

  首先我们需要创建一个继承ContentProvider的类,这里我命名为BookProvider,具体代码如下:

  1. public class BookProvider extends ContentProvider {
  2.  
  3. private static final String TAG = "BookProvider";
  4. @Override
  5. public boolean onCreate() {
  6. Log.d(TAG, "onCreate ,current thread:" + Thread.currentThread().getName());
  7. return false;
  8. }
  9.  
  10. @Nullable
  11. @Override
  12. public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
  13. Log.d(TAG, "query ,current thread:" + Thread.currentThread().getName());
  14. return null;
  15. }
  16.  
  17. @Nullable
  18. @Override
  19. public String getType(@NonNull Uri uri) {
  20. Log.d(TAG, "getType" );
  21. return null;
  22. }
  23.  
  24. @Nullable
  25. @Override
  26. public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
  27. Log.d(TAG, "insert" );
  28. return null;
  29. }
  30.  
  31. @Override
  32. public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
  33. Log.d(TAG, "delete" );
  34. return 0;
  35. }
  36.  
  37. @Override
  38. public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
  39. Log.d(TAG, "update" );
  40. return 0;
  41. }
  42.  
  43. }

  想要实现一个自定义的ContentProvider类需要实现上面6个抽象方法:

  • onCreate代表 ContentProvider的创建,在这个方法中做一些初始化的工作
  • getType用来返回一个Uri请求所对应的MIME类型(媒体类型),如果我们的应用不关心这个选项可以直接返回null或是"*/*",
  • query、insert、delete、update就分别对应对数据表的增删改查功能

  这里的除了onCreate方法由系统回调并运行在主线程里,其他五个方法由外界回调并运行在Binder线程池中。

  定义了一个这样的类之后,还需要在AndroidManifest中注册这个ContentProvider

  1. <provider
  2. android:name="provider.BookProvider"
  3. android:authorities="com.xw.provider"
  4. android:permission="com.xw.test.BookProvider"
  5. android:process="book.test"
  6. android:exported="true">
  7. </provider>
 

  其中前四个属性都是任意指定,android:exported表示是否允许外部程序访问ContentProvider,不过android:authorities是ContentProvider的唯一标识,外部应用就是通过这个属性来访问ContentProvider,所以android:authorities必须是唯一的。android:permission给我们的ContentProvider添加了权限,外部应用如果想要访问这个ContentProvider就必须声明这个"com.xw.test.BookProvider"权限,还要注意我们还需要这个权限属于我们自定义的所以需要加上:

  1. <permission android:name="com.xw.test.BookProvider"
  2. android:protectionLevel="normal"/>

  接下来是客户端,首先是同应用的一个Activity:

  1. public class ProviderActivity extends AppCompatActivity {
  2.  
  3. private static final String TAG = "BookProvider";
  4.  
  5. @Override
  6. protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_provider);
  9. Log.d(TAG, "ProviderActivity,onCreate ,current thread:" + Thread.currentThread().getName());
  10. Uri uri = Uri.parse("content://com.xw.provider");
  11. getContentResolver().query(uri,null,null,null,null);
  12. }
  13. }

  ContentProvider是通过Uri来指定使用的,这个Uri被称作内容Uri,内容Uri给ContentProvider中的数据提供了唯一的标识符,通常就是"content://"+authorities+表名。这里我们就可以直接指定为"content://com.xw.provider"。

  这里访问ContentProvider使用的是调用getContentResolver(),这个方法能得到一个ContentResolver类,通过这个ContentResolver类和Uri就能使用ContentProvider的query、insert、delete、update、getType五个方法。

  这里的输出是:

  1. 12-11 09:57:21.977 5551-5551/com.example.administrator.test D/BookProvider: ProviderActivity,onCreate ,current thread:main
  2. 12-11 09:57:22.079 5590-5590/book.test D/BookProvider: BookProvider,onCreate ,current thread:main
  3. 12-11 09:57:22.082 5590-5629/book.test D/BookProvider: query ,current thread:Binder:5590_3

  从输出我们可以看出ContentProvider的onCreate方法是运行在主线程里的。

  然后我们再创建一个新的应用测试一下真正的跨应用使用这个ContentProvider:

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. Uri uri = Uri.parse("content://com.xw.provider");
  8. getContentResolver().query(uri,null,null,null,null);
  9. }
  10. }

  Activity的代码和刚才一样,还要注意在AndroidManifest中加入权限:

  1. <uses-permission android:name="com.xw.test.BookProvider"/>

  输出:

  1. - ::54.304 -/? D/BookProvider: ProviderActivity,onCreate ,current thread:main
  2. - ::54.431 -/? D/BookProvider: BookProvider,onCreate ,current thread:main
  3. - ::54.434 -/? D/BookProvider: query ,current thread:Binder:16092_2

  如果是具体使用一个数据库的话,看这个android——实现跨程序访问数据

IPC机制2的更多相关文章

  1. Anciroid的IPC机制-Binder概述

    在Linux系统中,是以进程为单位分配和管理资源的.出于保护机制,一个进程不能直接访问另一个进程的资源,也就是说,进程之间互相封闭.但是,在一个复杂的应用系统中,通常会使用多个相关的进程来共同完成一项 ...

  2. Handler消息机制与Binder IPC机制完全解析

    1.Handler消息机制 序列 文章 0 Android消息机制-Handler(framework篇) 1 Android消息机制-Handler(native篇) 2 Android消息机制-H ...

  3. ndk学习15: IPC机制

    Linux IPC机制 来自为知笔记(Wiz)

  4. Android之IPC机制

    Android IPC简介 任何一个操作系统都需要有相应的IPC机制,Linux上可以通过命名通道.共享内存.信号量等来进行进程间通信.Android系统不仅可以使用了Binder机制来实现IPC,还 ...

  5. IPC机制--Binder

    文章来自 Android技术内幕 系统卷 转:http://www.linuxidc.com/Linux/2011-08/40508.htm 什么是IPC机制以及IPC机制的种类 在Linux中,是以 ...

  6. IPC机制

    转:http://blog.chinaunix.net/uid-26125381-id-3206237.html  IPC 三种通信机制 2012-05-13 17:23:55 最近看了,IPC三种通 ...

  7. IPC 机制简介

    IPC 机制简介 概述 在Unix早期发展中,做出重大贡献的两大主力Bell实验室和伯克利大学(BSD)在IPC(InterProcess Communication)方面的侧重点有所不同.前者对Un ...

  8. pipe()管道最基本的IPC机制

    <h4>进程间通信 fork pipe pie_t 等用法(管道机制 通信)</h4>每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之 ...

  9. Android的IPC机制(一)——AIDL的使用

    综述 IPC(interprocess communication)是指进程间通信,也就是在两个进程间进行数据交互.不同的操作系统都有他们自己的一套IPC机制.例如在Linux操作系统中可以通过管道. ...

  10. [置顶] 深入理解android之IPC机制与Binder框架

    [android之IPC机制与Binder框架] [Binder框架.Parcel.Proxy-Stub以及AIDL] Abstract [每个平台都会有自己一套跨进程的IPC机制,让不同进程里的两个 ...

随机推荐

  1. scrapy基础知识之 处理Redis里的数据:

    数据爬回来了,但是放在Redis里没有处理.之前我们配置文件里面没有定制自己的ITEM_PIPELINES,而是使用了RedisPipeline,所以现在这些数据都被保存在redis的xx:items ...

  2. 实现markdown功能

    前言 由于个人一直想弄一个博客网站,所以写博客的功能也就必须存在啦,而之前想过用富文本编辑器来实现的.但是接触了markdown后,发现真的是太好玩了,而且使用markdown的话可以在博客园.CSD ...

  3. Object.keys使用整理

    一.语法 Object.keys(obj) 参数:要返回其枚举自身属性的对象 返回值:一个表示给定对象的所有可枚举属性的字符串数组 二.处理对象,返回可枚举的属性数组 let person = { n ...

  4. 20190127-Orleans与SF小伙伴的部分问答

    Orleans 怎么部署到服务器? 方式1:Orleans 服务端寄宿在Web应用中,将Web应用部署到服务器 方式2:通过SF/K8s部署到服务器 不同服务器上的谷仓和谷如何调配? 由Orleans ...

  5. ASP.NET Core系列(二):创建第一个.Net Core 项目

    前面讲过 .NET Core简介及开发环境安装,本章会讲一讲ASP.NET Core 2.0的项目结构,查看完整的ASP.NET Core系列文章:https://www.cnblogs.com/zh ...

  6. .NET CORE 多语言实现方案

    根据市场需求,基于.NET CORE平台开发的RoadFlow工作流平台需要实现多语言版本.经过方案讨论和比对,决定采用.NET自带的本地化功能来实现多语言.话不多说,直接上实现方式. 首先修改Sta ...

  7. SpringBoot2.x 整合Spring-Session实现Session共享

    SpringBoot2.x 整合Spring-Session实现Session共享 1.前言 发展至今,已经很少还存在单服务的应用架构,不说都使用分布式架构部署, 至少也是多点高可用服务.在多个服务器 ...

  8. Jmeter--录制脚本-用户参数化-添加断言

    使用jmeter实现的场景 1.使用badboy录制脚本 2.使用jmeter自带元件进行用户参数化 3.给请求添加断言(给请求添加检查点) 使用badboy录制脚本导入jmeter 1.输入http ...

  9. 2019.6.16完成classstack任务

    最终信息 4 ShineEternal 任务完成,账号已注销 120 149 80.537%

  10. Excel催化剂开源第35波-图片压缩及自动旋转等处理

    Excel催化剂在图片处理方面,也是做到极致化,一般的Excel插件插入图片是原图插入或不可控制压缩比例地方式插入图片至Excel当中,但Excel催化剂的插入图片,是开发了可调节图片大小的插入方式, ...