第十章 进程间的通信 之 多进程(四)

文章目录

(一)多进程基础

1.1)多进程定义

当一个应用在开始运行时,系统会为它创建一个进程,一个应用默认只有一个进程,这个进程(主进程)的名称就是应用的包名。
为了彻底地解决应用内存(主进程占用内存超过内存限制)的问题,Android引入了多进程的概念,它允许在同一个应用内,为了分担主进程的压力,将占用内存的某些页面单独开一个进程,比如Flash、视频播放页面,频繁绘制的页面等。

1.2)进程等级

进程按优先级可分为五类,优先级从高到低排列:
在这里插入图片描述

(1)前台进程

该进程包含正在与用户进行交互的界面组件。

  1. 屏幕顶层运行Activity(处于onResume()状态),用户正与之交互
  2. 有BroadcastReceiver正在执行代码
  3. 有Service在其回调方法(onCreate()、onStart()、onDestroy())中正在执行代码
    这种进程较少,一般来作为最后的手段来回收内存

(2)可见进程

该进程中的组件虽然没有和用户交互,但是仍然可以被看到。

  1. 屏幕上显示Activity,但不可操作(处于onPause()状态)
  2. 有service通过调用Service.startForeground(),作为一个前台服务运行
  3. 含有用户意识到的特定的服务,如动态壁纸、输入法等

(3)服务进程

该进程包含在执行后台操作,用户不直接可见的服务组件,比如播放音乐的Service。对于许多在后台做处理(如加载数据)而没有立即成为前台服务的应用都属于这种情况。

(4)缓存/后台进程

该进程包含的组件没有与用户交互,用户也看不到 Service。在一般操作场景下,设备上的许多内存就是用在这上面的,使可以重新回到之前打开过的某个 activity 。

(5)空进程

没有任何界面组件、服务组件,或触发器组件,只是出于缓存的目的而被保留(为了更加有效地使用内存而不是完全释放掉),只要 Android 需要可以随时杀掉它们。

1.3)进程创建

Android多进程创建很简单,只需要在AndroidManifest.xml的声明四大组件的标签中增加”android:process”属性即可。命名之后,就成了一个单独的进程。

(1)私有进程

私有进程的名称前面有冒号,例如:

<service android:name=".MusicService"   
           android:process=":musicservice"/>

(2)全局进程

全局进程的名称前面没有冒号,例如:

<service android:name=".MusicService"   
           android:process="com.trampcr.musicdemo.service"/>

(3)初始化

多进程创建好,应用运行时会对进程进行初始化,如果一个application中有多个进程,进行全局初始化时,进程会被初始化多次。此时应该判断当前进程,做相应的初始化操作。

1.4)UID机制与共享进程

(1)UID机制

众所周知,Pid是进程ID,Uid是用户ID,只是Android和计算机不一样,计算机每个用户都具有一个Uid,哪个用户start的程序,这个程序的Uid就是那个那个用户,而Android中每个程序都有一个Uid,默认情况下,Android会给每个程序分配一个普通级别互不相同的Uid,如果用互相调用,只能是Uid相同才行,这就使得共享数据具有了一定安全性,每个软件之间是不能随意获得数据的。而同一个application只有一个Uid,所以application下的Activity之间不存在访问权限的问题。

(2)进程共享

a.一个application中共享service,provider或者activity等数据

1、完全暴露,这就是android:exported=”true”的作用,而一旦设置了intentFilter之后,exported就默认被设置为true了,除非再强制设为false。当然,对那些没有intentFilter的程序体,它的exported属性默认仍然是false,也就不能共享出去。
2、权限提示暴露,这就是为什么经常要设置usePermission的原因,如果人家设置了android:permission=”xxx.xxx.xx”那么,你就必须在你的application的Manufest中usepermission xxx.xxx.xx才能访问人家的东西。
3、私有暴露,假如说一个公司做了两个产品,只想这两个产品之间可互相调用,那么这个时候就必须使用shareUserID将两个软件的Uid强制设置为一样的。这种情况下必须使用具有该公司签名的签名文档才能,如果使用一个系统自带软件的ShareUID,例如Contact,那么无须第三方签名。

b.通过共享UID,使拥有同一个UID的多个APK可以配置成运行在同一进程中

1、在Manifest节点中增加android:sharedUserId属性。
2、在Android.mk中增加LOCAL_CERTIFICATE的定义。
如果增加了上面的属性但没有定义与之对应的LOCAL_CERTIFICATE的话,APK是安装不上去的。提示错误是:Package com.test.MyTest has no signatures that match those in shared user android.uid.system; ignoring!也就是说,仅有相同签名和相同sharedUserID标签的两个应用程序签名都会被分配相同的用户ID。例如所有和media/download相关的APK都使用android.media作为sharedUserId的话,那么它们必须有相同的签名media。
3、把APK的源码放到packages/apps/目录下,用mm进行编译。

(二)多进程通信IPC

2.1)Binder机制

1、定义

a.Linux内核基础知识

(1)用户空间/内核空间
用户空间指的是用户程序所运行的空间,内核空间是 Linux 内核的运行空间,为了安全,它们是隔离的,即使用户的程序崩溃了,内核也不受影响。
(2)系统调用——用户空间访问内核空间
用户空间访问内核空间的唯一方式就是系统调用;通过这个统一入口接口,所有的资源访问都是在内核的控制下执行,以免导致对用户程序对系统资源的越权访问,从而保障了系统的安全和稳定。
(3)Binder驱动——用户空间A访问用户空间B
在 Android 系统中,这个运行在内核空间的,负责各个用户进程通过 Binder 通信的内核模块叫做 Binder 驱动。

b.什么是Binder

  1. 直观来说,Binder是Android中的一个类,它继承了IBinder接口
  2. 从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在linux中没有
  3. 从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,etc)和相应ManagerService的桥梁
  4. 从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当你bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务

c.Binder优势

在传统的Linux上,我们还是有很多选择可以用来实现进程间通信,如管道、SystemV、Socket等。那么Android为什么不使用这些原有的技术,而是要使开发一种新的叫Binder的进程间通信机制呢?
主要有三个方面的原因:

(1)性能方面

在移动设备上(性能受限制的设备,比如要省电),广泛地使用跨进程通信对通信机制的性能有严格的要求,Binder相对于传统的Socket方式,传输效率高、开销小。Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次;共享内存方式虽然一次内存拷贝都不需要,但控制复杂,难以使用。

(2)安全方面

传统的进程通信方式对于通信双方的身份并没有做出严格的验证,使用传统IPC只能由用户在数据包里填入UID/PID,这样不可靠,容易被恶意程序利用。可靠的身份标记只有由IPC机制本身在内核中添加。比如Socket通信ip地址是客户端手动填入,很容易进行伪造,而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。

(3)实现面象对象的调用方式

在使用Binder时就和调用一个本地实例一样。

2、C/S通信方式

Binder使用Client-Server通信方式:一个进程作为Server提供诸如视频/音频解码,视频捕获,地址本查询,网络连接等服务;多个进程作为Client向Server发起服务请求,获得所需要的服务。
要想实现Client-Server通信据必须实现以下两点:
一是server必须有确定的访问接入点或者说地址来接受Client的请求,并且Client可以通过某种途径获知Server的地址;
二是制定Command-Reply协议来传输数据。Binder可以看成Server提供的实现某个特定服务的访问接入点, Client通过这个‘地址’向Server发送请求来使用该服务;对Client而言,Binder可以看成是通向Server的管道入口,要想和某个Server通信首先必须建立这个管道并获得管道入口。遍布于Client中的入口可以看成指向这个Binder对象的‘指针’,一旦获得了这个‘指针’就可以调用该对象的方法访问Server。

3、通信模型

Binder框架定义了四个角色:Server,Client,ServiceManager(以后简称SMgr)以及Binder驱动。其中Server,Client,SMgr运行于用户空间,驱动运行于内核空间。
理解:
这四个角色和互联网类似:Server是服务器,Client是客户终端,SMgr是域名服务器(DNS),Binder驱动是路由器。
和电话类似:Client给Server打电话,SMgr是通讯录,Binder是电话基站。

3.1)Binder驱动

驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。

3.2)ServiceManger进程

ServiceManager的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。

3.3)Server进程

提供服务的进程。
Service 向ServerManager 注册 实名Binder
Server创建了Binder实体,为其取一个字符形式,可读易记的名字,将这个Binder连同名字以数据包的形式通过Binder驱动发送给SMgr,通知SMgr注册一个名叫张三的Binder,它位于某个Server中。驱动为这个穿过进程边界的Binder创建位于内核中的实体节点以及SMgr对实体的引用,将名字及新建的引用打包传递给SMgr。SMgr收数据包后,从中取出名字和引用填入一张查找表中。

3.4)Client进程

使用服务的进程。
Client 向ServerManager 获得 实名Binder 的引用
Server向SMgr注册了Binder实体及其名字后,Client就可以通过名字获得该Binder的引用了。Client也利用保留的0号引用向SMgr请求访问某个Binder:我申请获得名字叫张三的Binder的引用。SMgr收到这个连接请求,从请求数据包里获得Binder的名字,在查找表里找到该名字对应的条目,从条目中取出Binder的引用,将该引用作为回复发送给发起请求的Client。
在这里插入图片描述

  1. Client、Server和Server Manager实现在用户空间中,Binder驱动程序实现在内核空间中
  2. Binder驱动程序和Service Manager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server
  3. Binder驱动程序提供设备文件/dev/binder与用户空间交互,Client、Server和Service Manager通过open和ioctl文件操作函数与Binder驱动程序进行通信
  4. Client和Server之间的进程间通信通过Binder驱动程序间接实现
  5. Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力

4、工作流程(代理Proxy模式)

实例:客户端向调用服务端的add方法,返回一个Object对象
在这里插入图片描述

步骤1:ServiceManager内维护了一张表,表存储着向他注册过的进程信息

在通信之初,首先需要有一个进程向驱动申请成为ServerManager,当内核驱动同意之后,这个成为ServerManager的进程就负责管理所有需要通信的进程信息

步骤2:服务端进程向ServerManager注册信息

服务端进程首先会向ServerManager注册一张表,这个表中就存储了相关信息,告诉ServerManager我这里有一个返回值为Object的add方法,

步骤3:客户端进程向ServerManager取得信息,通过Binder驱动与服务端进程通信

当ServerManger保存完毕后,客户端进程就会通过Binder驱动向ServerManger查询服务端进程的信息,ServerManage就会将服务端进程的信息返回给客户端进程,客户端与服务端进程之间就可以通过这些信息,利用Binder驱动来进行通信

2.2)AIDL

1、定义

AIDL(Android Interface Define Language) 是IPC进程间通信方式的一种.用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码.

2、使用

2.1)实例说明

假设一个情景我们需要计算a+b,我们需要在客户端传递两个参数a和b,然后将参数传递给服务端(另一个进程)来进行计算,计算结果传递给客户端。

2.2)新建一个项目作为服务端,在项目中创建AIDL文件

命名为IImoocAIDL.aidl,点击同步sycn project,查看build内是否自动生成IImoocAIDL文件

// IImoocAIDL.aidl
package com.mecury.aidltest;
// Declare any non-default types here with import statements
interface IImoocAIDL {    
    //计算num1 + num2    
    int add(int num1,int num2);
}

2.3)自动生成AIDL文件

根据自动生成的AIDL文件分析AIDL通信原理:
文件有一个叫做proxy的类,这是一个代理类,这个类运行在客户端中,其实AIDL实现的进程间的通信并不是直接的通信,客户端和服务端都是通过proxy来进行通信的:客户端调用的方法实际是调用是proxy中的方法,然后proxy通过和服务端通信将返回的结果返回给客户端。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: F:\\AS for android\\AIDLTest\\aidlclient\\src\\main\\aidl\\com\\mecury\\aidltest\\IImoocAIDL.aidl
 */
package com.mecury.aidltest;
// Declare any non-default types here with import statements

public interface IImoocAIDL extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.mecury.aidltest.IImoocAIDL {
        private static final java.lang.String DESCRIPTOR = "com.mecury.aidltest.IImoocAIDL"; //Binder的唯一标识

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.mecury.aidltest.IImoocAIDL interface,
         * generating a proxy if needed.
         */
        //将服务端的Binder对象转换成客户需要的AIDL对象,转换区分进程,客户端服务端位于同一进程,返回服务端的
        //Stub对象本身;否则返回的是系统的封装后的Stub.proxy对象。
        public static com.mecury.aidltest.IImoocAIDL asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.mecury.aidltest.IImoocAIDL))) {
                return ((com.mecury.aidltest.IImoocAIDL) iin);
            }
            return new com.mecury.aidltest.IImoocAIDL.Stub.Proxy(obj);
        }
        //返回当前Binder对象
        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        //运行在服务端的Binder线程池中
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_add: {
                    data.enforceInterface(DESCRIPTOR);
                    //读取客户端传递过来再data中存储的方法的参数
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    //调用方法
                    int _result = this.add(_arg0, _arg1);
                    //将计算结果写入reply中
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags); //向Transact传递数据
        }
        
        //代理类,运行在客户端
        private static class Proxy implements com.mecury.aidltest.IImoocAIDL {
            private android.os.IBinder mRemote; //声明一个IBinder对象

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }
            //返回当前Binder对象
            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            } 

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }
            
            //客户端调用此方法,传递进来num1和num2两个参数,
            @Override
            public int add(int num1, int num2) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    //向_data中写入参数
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(num1);
                    _data.writeInt(num2);
                    //通过transact方法向服务端传递参数,并调用了方法,返回的结果写入_reply中
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
        //标识位
        static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
    
    //计算num1 + num2
    public int add(int num1, int num2) throws android.os.RemoteException;
}

代码中方法说明:
(1)DESCRIPTION
Binderd的唯一标识,一般用当前的类名表示。
asInterface(android.os.IBinder obj)
用于将服务端的Binder对象转换为客户端需要的AIDL接口类型的对象,转换区分进程,客户端服务端位于同一进程,返回服务端的 //Stub对象本身;否则返回的是系统的封装后的Stub.proxy对象。
(2)asBInder
返回Binder对象
(3)onTransact
此方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。
(4)Proxy#add
此方法运行在客户端,当客户端远程调用此方法时,它的内部实现是这样的:首先创建该方法所需要的输入型Parcel对象_data、输出型Parcel对象_reple和返回值对象_result,然后将该方法的参数信息写入_data中;接着调用transact方法来发RPC请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程返回的结果,写入_result中。

2.4)新建客户端

File-》new–》new module–》phone & table module。命名为aidlclient.java。同样要在客户端创建AIDL文件,里面的包名和所在位置要求完全一样。

2.5)在服务端创建一个Service用来监听客户端连接请求

public class IRemoteService extends Service {

    //客户端绑定service时会执行
    @Override
    public IBinder onBind(Intent intent) {
        return iBinder;
    }

    private IBinder iBinder = new IImoocAIDL.Stub(){

        @Override
        public int add(int num1, int num2) throws RemoteException {
            Log.e("TAG","收到了来自客户端的请求" + num1 + "+" + num2 );
            return num1 + num2;
        }
    };
}

2.6)在AndroidMainfest.xml注册Service

<service android:name=".IRemoteService"
            android:process=":remote"
            android:exported="true">
            <intent-filter>
                <action android:name="com.mecury.aidltest.IRomoteService"/>
            </intent-filter>
</service>

2.7)客户端绑定服务并调用服务端方法

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText num1;
    private EditText num2;
    private Button button;
    private TextView text;

    private IImoocAIDL iImoocAIDL;

    private ServiceConnection conn = new ServiceConnection() {

        //绑定服务,回调onBind()方法
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iImoocAIDL = IImoocAIDL.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iImoocAIDL = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bindService();
        initView();

    }

    private void initView() {
        num1 = (EditText) findViewById(R.id.num1);
        num2 = (EditText) findViewById(R.id.num2);
        button = (Button) findViewById(R.id.button);
        text = (TextView) findViewById(R.id.text);

        button.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        int num11 = Integer.parseInt(num1.getText().toString());
        int num22 = Integer.parseInt(num2.getText().toString());

        try {
            int res = iImoocAIDL.add(num11,num22);
            text.setText(num11 +"+"+ num22 +"="+ res);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private void bindService() {

        Intent intent = new Intent();
        //绑定服务端的service
        intent.setAction("com.mecury.aidltest.IRomoteService");
        //新版本(5.0后)必须显式intent启动 绑定服务
        intent.setComponent(new ComponentName("com.mecury.aidltest","com.mecury.aidltest.IRemoteService"));
        //绑定的时候服务端自动创建
        bindService(intent,conn, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
}

3、AIDL支持的数据类型

  • 基本数据类型(int、long、char 等)
  • String 和 CharSequence
  • List:只支持ArrayList,里面的每个元素都必须被AIDL支持。
  • Map: 只支持HashMap, 里面的每个元素都必须被AIDL支持。
  • Parcelable: 所有实现了Parcelable接口的对象
  • AIDL: 所有的AIDL接口本身也可以在AIDL文件中使用

4、自定义类型

AIDL能够传输的数据类型有限制,这里必须将book序列化才能够使用,同时Book类在客户端和服务端都要这样定义

4.1)自定义类型文件

Book.java

public class Book implements Parcelable {
    public int bookId;
    public String bookName;

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);
    }

    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    @Override
    public String toString() {
        return bookId + ":" + bookName;
    }
}

4.2)AIDL文件

Book.aidl

package com.mecury.aidltest2;
parcelable Book;

IOnNewBookArrivedListener.aidl

package com.mecury.aidltest2;

import com.mecury.aidltest2.book;
interface IOnNewBookArrivedListener {
     void OnNewBookArrivedListener(in Book book);
}

IBookManager.aidl

package com.mecury.aidltest2;
import com.mecury.aidltest2.book;
import com.mecury.aidltest2.IOnNewBookArrivedListener;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrivedListener listener);
void unregisterListener(IOnNewBookArrivedListener listener);
}

4.3)服务端文件

public class BookManagerService extends Service {

    private static final String TAG = "BMS";

    private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);
    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
    private RemoteCallbackList<IOnNewBookArrivedListener> mListeners = new RemoteCallbackList<>();

    //创建一个Binder对象
    private Binder mBinder = new IBookManager.Stub(){

        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            mBookList.add(book);
        }

        @Override
        public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
            mListeners.register(listener);
        }

        @Override
        public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
            mListeners.unregister(listener);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        mBookList.add(new Book(1,"Android"));
        mBookList.add(new Book(2, "Ios"));
        new Thread(new serviceWork()).start();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    //将book添加到图书列表中(mBookList),并通知所有观察者
    private void onNewBookArrived(Book book) throws RemoteException {
        mBookList.add(book);
        final int N = mListeners.beginBroadcast();
        Log.e("onNewBookArrived","registener listener size:" + N);
        for (int i = 0; i < N; i++){
            IOnNewBookArrivedListener l = mListeners.getBroadcastItem(i);
            if (l!=null){
                l.OnNewBookArrivedListener(book);
            }
        }
        mListeners.finishBroadcast();
    }
    //线程类。在每休眠5秒后,会自动添加一本书, 并通过OnNewBookArrived()方法通知所有观察者。 
    private class serviceWork implements Runnable{

        @Override
        public void run() {
            while (!mIsServiceDestoryed.get()){
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int bookId = mBookList.size() + 1;
                Book newBook = new Book(bookId,"new Book #" + bookId);

                try {
                    onNewBookArrived(newBook);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void onDestroy() {
        mIsServiceDestoryed.set(true);
        super.onDestroy();
    }
}

4.4)客户端文件

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "BookManagerActivity";
    private IBookManager bookManager;
    private static final int MESSAGE_NEW_BOOK_ARRIVED = 1;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MESSAGE_NEW_BOOK_ARRIVED:
                    Log.e(TAG, "received new book:" + msg.obj);
                    break;
                default:
                    super.handleMessage(msg);
            }

        }
    };

    private ServiceConnection mService = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            bookManager = IBookManager.Stub.asInterface(service);
            try {
                List<Book> list = bookManager.getBookList();
                Log.e(TAG, "query book list,list type:" + list.getClass().getCanonicalName());
                Log.e(TAG, "query book list:" + list.toString());
                Book newBook = new Book(3, "android进阶");
                bookManager.addBook(newBook);
                Log.e(TAG, "add book:" + newBook);
                List<Book> newList =  bookManager.getBookList();
                Log.e(TAG, "query book list:" + newList.toString());
                bookManager.registerListener(mNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            bookManager = null;
            Log.e(TAG, "binder died.");
        }
    };

    private IOnNewBookArrivedListener mNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
        @Override
        public void OnNewBookArrivedListener(Book book) throws RemoteException {
            mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, book).sendToTarget();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bindService();

    }

    private void bindService() {
        Intent intent = new Intent();
        intent.setAction("com.mecury.aidltest2.BookManagerService");
        intent.setComponent(new ComponentName("com.mecury.aidltest2", "com.mecury.aidltest2.BookManagerService"));
        bindService(intent, mService, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        if (bookManager != null && bookManager.asBinder().isBinderAlive()){
            Log.e(TAG, "unregister listener:" + mNewBookArrivedListener);
            try {
                bookManager.unregisterListener(mNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        unbindService(mService);
        super.onDestroy();
    }
}

2.3)Messenger

1、定义

使用Messenger为服务提供接口,让服务与远程进程通信。利用Handler实现。(适用于多进程、单线程,不需要考虑线程安全),其底层基于AIDL。

2、使用

2.1)服务端实现一个Handler,接受来自客户端每个调用的回调

Handler用于创建Messenger对象(对Handler的引用),Messenger创建一个IBinder.服务通过onBind()使其返回客户端;并在其Handler(handleMessage())中接收每个Message。

public class MessengerService extends Service{

    class IncomingHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    Toast.makeText(getApplicationContext(), "hello, trampcr", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }

    Messenger mMessenger = new Messenger(new IncomingHandler());

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
}

2.2)在AndroidManifest.xml声明

在AndroidManifest.xml中声明并给一个进程名,使该服务成为一个单独的进程

<service android:name=".MessengerService"  
         android:process="com.trampcr.messenger.service"/>

2.3)客户端使用IBinder将Messenger(引用服务的Handler)实例化,然后使用后者将Message对象发送给服务

public class MessengerActivity extends Activity{

    private boolean mBound;
    private Messenger mMessenger;
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mMessenger = new Messenger(service);
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mMessenger = null;
            mBound = false;
        }
    };

    public void sayHello(View v){
        if(!mBound){
            return;
        }
        Message msg = Message.obtain(null, 0 , 0, 0);
        try {
            mMessenger.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(MessengerActivity.this, MessengerService.class);
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(mBound){
            unbindService(mServiceConnection);
            mBound = false;
        }
    }
}

3、AIDL与Messenger、Binder区别

Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.
(1)只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL
(2)如果进程间的通信来自同一应用,应该使用Binder
(3)如果进程间的通信不需要处理多线程,应该使用Messenger
a.Messenger不适用大量并发的请求:Messenger以串行的方式来处理客户端发来的消息,如果大量的消息同时发送到服务端,服务端仍然只能一个个的去处理。
b.Messenger主要是为了传递消息:对于需要跨进程调用服务端的方法,这种情景不适用Messenger。
c.Messenger的底层实现是AIDL,系统为我们做了封装从而方便上层的调用。
d.AIDL适用于大量并发的请求,以及涉及到服务端端方法调用的情况

发布了74 篇原创文章 · 获赞 15 · 访问量 6255

猜你喜欢

转载自blog.csdn.net/qq_29966203/article/details/90518716