Android开发艺术探索-第二章-IPC机制

layout: post
date: 2015-12-28
title: Android开发艺术探索-第二章-IPC机制
categories: blog
tags: [Activity,Android]
category: Android
description:

本文首发于KuTear,转载请注明

2.1 Android IPC

Android常用进程间通信

  1. Binder
  2. Socket
  3. ContentProvider
  4. 文件共享(SharePreference/普通文件/数据库) 对同步要求不是很高才使用,不建议使用SharePreference.

2.2 Android多进程

  1. 开启方式

    在AndroidMenifest中为四大组件指定android:process=””属性 <br />
    默认进程名字为包名,指定 android:process=”:##” 的进程名为 包名:##,该进程为当前App的私有进程,其他应用的组件不可以和他跑在同一进程中.其他类型的进程可以通过ShareUID共享(签名相同)

  2. 多进程的运行

    在不同进程中的四大组件,不能通过内存来共享数据.静态字段在不同的进程有不同的副本,且互不影响.不同进程含有不同的Application引用(开启进程会为该进程创建Application).

2.3 IPC基础介绍

  1. 序列化

    • Serializable

      静态成员变量属于类而不属于对象,不会参与序列化过程,其次使用transient(短暂)标志的成员变量也不会参与序列化过程.

      序列化到本地

             User user = new User(1, "hello world", false);
             File cachedFile = new File(MyConstants.CACHE_FILE_PATH);
             ObjectOutputStream objectOutputStream = null;
             try {
                 objectOutputStream = new ObjectOutputStream(
                         new FileOutputStream(cachedFile));
                 objectOutputStream.writeObject(user);
             } catch (IOException e) {
                 e.printStackTrace();
             } finally {
                 //数据流关闭
             }
      

      从本地恢复序列化

             User user = null;
             File cachedFile = new File(MyConstants.CACHE_FILE_PATH);
             if (cachedFile.exists()) {
                 ObjectInputStream objectInputStream = null;
                 try {
                     objectInputStream = new ObjectInputStream(
                             new FileInputStream(cachedFile));
                     user = (User) objectInputStream.readObject();
                 } catch (IOException e) {
                     e.printStackTrace();
                 } catch (ClassNotFoundException e) {
                     e.printStackTrace();
                 } finally {
                     //数据流关闭
                 }
             }
      
    • Parcelable

      在Android Studio中可以利用插件自动生成.注意boolean转化为int/byte存储

        @Override
        public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(this.id);
             dest.writeByte(isFirst ? (byte) 1 : (byte) 0);
        }
        protected Demo(Parcel in) {
             this.id = in.readInt();
             this.isFirst = in.readByte() != 0;
        }
      

      相比Serializable,Parcelable的性能更好,Serializable需要大量的I/O操作

    • Binder

2.4 Android中的IPC

  • Bundle

    在Service,Activity,Receiver中使用Intent传递Bundle对象,在日常开发的过程中,对同一线程的通信也使用的比较多.前面说过,支持基本的类型和实现序列化的类

  • 文件共享

    在A进程向文件xxx写入,在B进程从文件xxx读出内容,需要注意的就是同步问题,前面说过不要使用SharePreference.

  • Messenger

    Messenger实质上还是AIDL,不过使用变得相当的简单.
    下面是一个栗子:
    创建一个Service(MessengerService.java),并指定进程,其主要代码为:

           //接收客户端的数据并做出反馈
           private static class MessengerHandler extends Handler {
               @Override
               public void handleMessage(Message msg) {
                   super.handleMessage(msg);
                   Log.v(TAG, msg.what + "");
                   Messenger reply = msg.replyTo;
                   Message replymsg = Message.obtain();
                   replymsg.what = msg.what * 2;
                   try {
                       reply.send(replymsg);
                   } catch (RemoteException e) {
                       e.printStackTrace();
                   }
               }
           }
       
           private Messenger messenger = new Messenger(new MessengerHandler());
       
           @Override
           public IBinder onBind(Intent intent) {
               return messenger.getBinder();
           }
    

    在Activity中链接该服务

           //处理服务端返回的数据
           private static class MessagerHandler extends Handler {
               @Override
               public void handleMessage(Message msg) {
                   super.handleMessage(msg);
                   Log.v(TAG, msg.what + "");
               }
           }
       
           private ServiceConnection connection = new ServiceConnection() {
               @Override
               public void onServiceConnected(ComponentName name, IBinder service) {
                   Messenger messenger = new Messenger(service);
                   Message msg = Message.obtain();
                   msg.what = 1024;
                   //指定接收服务端返回的数据的处理者
                   msg.replyTo = new Messenger(new MessagerHandler());
                   try {
                   //向服务端发送数据    
                       messenger.send(msg);
                   } catch (RemoteException e) {
                       e.printStackTrace();
                   }
               }
       
               @Override
               public void onServiceDisconnected(ComponentName name) {
       
               }
           };
       
           @Override
           protected void onCreate(Bundle savedInstanceState) {
               super.onCreate(savedInstanceState);
               setContentView(R.layout.activity_messager);
       
               Intent intent = new Intent(this, MessengerService.class);
               bindService(intent, connection, BIND_AUTO_CREATE);
           }
    

    Messenger串行处理客户端的消息,Message的object不能在跨进程中来传递非系统自定义的Parcelable数据,只能在Bundle中传递.

  • AIDL

    注意点:需要在AIDl中使用的已经序列化好了的对象必须编写对应的aidl文件声明(Book.java–>Book.aidl)

       // Book.aidl
       package com.kutear.studydemo.android.art.aidl;
       
       // Declare any non-default types here with import statements
       
       parcelable Book;
    

    aidl中使用到的类必须按全路径导入.即使在同包下

       // IBookManager.aidl
       package com.kutear.studydemo.android.art.aidl;
       //同路径任导入
       import com.kutear.studydemo.android.art.aidl.Book;
       import com.kutear.studydemo.android.art.aidl.IListener;
       
       // Declare any non-default types here with import statements
       
       interface IBookManager {
           void addBook(in Book book);
           List<Book> getBookList();
           void registerListener(IListener listener);
           void unregisterListener(IListener listener);
       }
    

    创建Service(服务端)

       public class AidlService extends Service {
    
           private static final String TAG = "AidlService";
           
           private CopyOnWriteArrayList<Book> books = new CopyOnWriteArrayList<>();
           private ArrayList<IListener> mListeners = new ArrayList<>();
           private Binder mBinder = new IBookManager.Stub() {
           
                   @Override
                   public void addBook(Book book) throws RemoteException {
                       books.add(book);
                       displayListener(book);
                   }
           
                   @Override
                   public List<Book> getBookList() throws RemoteException {
                       return books;
                   }
           
                   @Override
                   public void registerListener(IListener listener) throws RemoteException {
                       //listener-->com.kutear.studydemo.android.art.aidl.IListener$Stub$Proxy@41895598
                       //同加进来的对象类型都变了
                       if (listener != null) {
                               Log.v(TAG, listener.toString());
                               mListeners.add(listener);
                       }
                   }
           
                   @Override
                   public void unregisterListener(IListener listener) throws RemoteException {
                       if (listener != null) {
                               mListeners.remove(listener);
                       }
                   }
           };
           
           public AidlService() {
           }
           
           //观察者模式分发
           private void displayListener(Book book) {
               for (IListener listener : mListeners) {
                   try {
                           listener.newBookArrived(book);
                   } catch (RemoteException e) {
                           e.printStackTrace();
                   }
               }
           }
           
           @Override
           public IBinder onBind(Intent intent) {
                   return mBinder;
           }
           
           @Override
           public void onCreate() {
                   super.onCreate();
                   books.add(new Book(1, "HTTP"));
                   books.add(new Book(2, "TCP"));
           }
       }
    

    在Activity中进行绑定(客户端)

       //注意这里不能直接new IListener(),因为跨进程过程中对象的还原是基于序列化
       //,也就是说还原后的对象已经不是原本的对象
       //在AidlService#mBinder#registerListener(IListener listener)中的
       //listener实际是不等于直接创建的mListener的
       //导致在分发的时候本地无法回调
       private IListener mListener = new IListener.Stub() {
    
           @Override
           public void newBookArrived(Book book) throws RemoteException {
               Log.v(TAG,"NewBook"+book.toString());
               //运行在客户端的Binder线程池中,非UI线程,不能操作UI,
               //使用Hanlder切换至主线程
           }
       };
    
       private ServiceConnection connection = new ServiceConnection() {
           @Override
           public void onServiceConnected(ComponentName name, IBinder service) {
               IBookManager bookManager = IBookManager.Stub.asInterface(service);
               try {
                   Log.v(TAG, bookManager.getBookList().toString());
                   //mListener = com.kutear.studydemo.android.art.demo2.AidlActivity$1@41900c48
                   bookManager.registerListener(mListener);
                   bookManager.addBook(new Book(100, "Android"));
               } catch (RemoteException e) {
                   e.printStackTrace();
               }
           }
    
           @Override
           public void onServiceDisconnected(ComponentName name) {
    
           }
       };
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_aidl);
    
           Intent intent = new Intent(this, AidlService.class);
           bindService(intent, connection, BIND_AUTO_CREATE);
       }
    

    在客户端调用服务端的函数,运行在服务端的Binder线程池中,若该函数是耗时操作,则需要在客户端开启异步线程来操作.否则ANR

    注意使用类RemoteCallbackList来实现注册与解除注册,原因就是代码中的注释部分,对象重新生成过

    <b>权限控制</b>

           @Override
           public IBinder onBind(Intent intent) {
               int check = checkCallingOrSelfPermission("permission_name");
               if(check == PackageManager.PERMISSION_DENIED){
                   //授权失败
                   //TODO
               }else{
                   //授权成功
                   //TODO
               }
               return mBinder;
           }
    
  • ContentProvider

    主要的类就是ContentProvider(提供内容),ContentResolver(解析内容).自定义类继承至ContentProvider,实现基本的CURL方法.注意SQLiteDatabase本身是处理了同步的.
    ContentProvider的onCreate在主线程执行,其余函数在Binder线程池中执行,需要注意的是同步问题.
    除了基本的增删改之外,还可以调用自定义的方法.下面是个栗子.

           //ContentProvider
           public String customMethod(){
               Log.v(TAG,"function customMethod");
               return "Hello";
           }
       
           @Nullable
           @Override
           public Bundle call(String method, String arg, Bundle extras) {
               if(method.equals("customMethod")){
                   customMethod();
                   //TODO 封装Bundle返回 
                   //returm bundle;
               }
               return super.call(method, arg, extras);
           }
    

    在需要的地方调用

        Bundle bundle =    getContentResolver().call(uri,"customMethod",null/*arg*/,null/*extras*/);
    
  • Socket

    利用Socket来进程间的通信同在java中利用Socket通信是一模一样的,只是需要注意的就是一定不要在主线程通信.

2.5 Binder线程池

  • 多个AIDL绑定在一个Service上

    实现过程为在IBinderPool中绑定Service,获取到AIDL实现的一个IBinder(暂命名iquery,在service中返回的.包含一个查询其他AIDL的IBinder的方法)
    在IBinderPool中实现查询的方法,实现部分通过iquery的方法.

2.6 选择合适的IPC

《Android开发艺术探索-第二章-IPC机制》 选择合适的IPC

参考

Art of Android Development Reading Notes 2

    原文作者:KuTear
    原文地址: https://www.jianshu.com/p/7b0be4d0f8f0
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞