Android进程间通讯详解

因为android系统中应用程序之间不能共享内存。所以,在不一样应用程序之间交互数据(跨进程通信)就稍微麻烦一些。

进程间通讯(ipc)html

IPC方法老是产生客户/服务端模式的调用,也便是客户端组件(Activity/Service)持有服务端Service的组件,只能是客户端主动调用服务端的方法,服务端没法反过来调用客户端的方法,由于IPC的另外一端Service没法获取客户端的对象。linux

binderandroid

Binder 是一种进程间通讯机制。安卓中跨进程通信就是经过binder。当绑定服务的时候会返回一个binder对象,而后经过他进行多进程间的通讯。Binder只须要一次数据拷贝,性能上仅次于共享内存。多线程

在 Android 系统中,这个运行在内核空间,负责各个用户进程经过 Binder 实现通讯的内核模块就叫 Binder 驱动(Binder Dirver)。并发

Binder IPC 机制中涉及到的内存映射经过 mmap() 来实现,mmap() 是操做系统中一种内存映射的方法。内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系创建后,用户对这块内存区域的修改能够直接反应到内核空间;反以内核空间对这段区域的修改也能直接反应到用户空间。app

内存映射能减小数据拷贝次数,实现用户空间和内核空间的高效互动。两个空间各自的修改能直接反映在映射的内存区域,从而被对方空间及时感知。也正由于如此,内存映射可以提供对进程间通讯的支持。ide

Binder IPC 正是基于内存映射(mmap)来实现的
Android进程间通讯详解Android进程间通讯详解
Binder 通讯中的代理模式
咱们已经解释清楚 Client、Server 借助 Binder 驱动完成跨进程通讯的实现机制了,可是还有个问题会让咱们困惑。A 进程想要 B 进程中某个对象(object)是如何实现的呢?毕竟它们分属不一样的进程,A 进程 无法直接使用 B 进程中的 object。函数

前面咱们介绍过跨进程通讯的过程都有 Binder 驱动的参与,所以在数据流经 Binder 驱动的时候驱动会对数据作一层转换。当 A 进程想要获取 B 进程中的 object 时,驱动并不会真的把 object 返回给 A,而是返回了一个跟 object 看起来如出一辙的代理对象 objectProxy,这个 objectProxy 具备和 object 一摸同样的方法,可是这些方法并无 B 进程中 object 对象那些方法的能力,这些方法只须要把把请求参数交给驱动便可。对于 A 进程来讲和直接调用 object 中的方法是同样的。性能

当 Binder 驱动接收到 A 进程的消息后,发现这是个 objectProxy 就去查询本身维护的表单,一查发现这是 B 进程 object 的代理对象。因而就会去通知 B 进程调用 object 的方法,并要求 B 进程把返回结果发给本身。当驱动拿到 B 进程的返回结果后就会转发给 A 进程,一次通讯就完成了
Android进程间通讯详解Android进程间通讯详解
其实进程间通讯就是为了实现数据共享。一个程序不一样组件在不一样进程也叫多进程,和俩个应用没有本质区别。使用process属性能够实现多进程,可是会带来不少麻烦,主要缘由是共享数据会失败,弊端有:静态和单利失效,同步失效,sharedprefer也变的不可靠等问题。操作系统

多进程通讯的方式

1.使用intent的附加信息extras来传递,经过bundle,传递的是bundle支持的类型,好比基本数据类型、实现pracellable或serializeable的对象

/**指定包名和带包名的Activity的名字*/
ComponentName componentName = new ComponentName("com.example.androidaidl", "com.example.androidaidl.MainActivity");
Intent intent = new Intent();
intent.putExtra("id", 1001);
intent.setComponent(componentName);
startActivity(intent);

2.使用文件共享,序列化或是sharedpre,不过不适用于读写并发的操做
3.广播:Android的广播是系统级的,只要传递的Action同样,就能够接收到其余进程广播的消息,广播中能够经过Intent传递数据。
4.scheme协议是android中的一种页面内跳转协议,经过定义本身的scheme协议,能够很是方便跳转app中的各个页面,而且传递数据,仍是能够经过H5页面跳转指定页面等。
5.ContentProvider(进程间数据共享)和message同样,底层也是binder,除了oncreate方法其余方法(crud)都是运行在bindler线程里。因此在oncerate里不能作耗时操做。Android自己就提供了很多的ContentProvider访问,好比联系人、相册等。 访问ContentProvider,须要经过Uri,须要以“content://”开头。在其余应用访问经过uri(主机名):

ContentResolver resolver = getActivity().getContentResolver();
/**com.mh.getdata/stock这个要和Provider所在进程中添加的Uri一致*/
Uri uri = Uri.parse("content://com.mh.getdata/stock");
Cursor cursor = resolver.query(uri, null, null, null, null);

常规通信

只有容许不一样应用的客户端用 IPC 方式访问服务,而且想要在服务中处理多线程(多任务)时,才有必要使用 AIDL。 若是您不须要执行跨越不一样应用的并发 IPC,就应该经过实现一个 Binder 建立接口;或者,若是您想执行 IPC,但根本不须要处理多线程,则使用 Messenger 类来实现接口。不管如何,在实现 AIDL 以前,请您务必理解绑定服务。
aidl文档

1.经过 Messenger进行传递(handler),在远程服务里建立handler(接收客户端发送的消息)、 Messenger对像,在onbind里返回( Messenger.getbinder)。在客户端绑定服务,拿着 Messenger对象发消息(能够用bundle)。在远程服务的handlermessage方法就会收到。他是一个个处理的,若是大量并发请求用aidl, Messenger底层就是aidl

在客户端中建立一个Messenger。而后,当客户端收到 onServiceConnected() 回调时,会向服务发送一条 Message,并在其 send() 方法的 replyTo 参数中包含客户端的 Messenger。
注意:Messenger和Message是俩个东西

public void sayHello(View v) {

        if (!mBound) return;
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
           mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

2.直接使用Binder对象:缺点是这种方式不能进行跨进程,跨应用程序的函数调用。只能实如今同一个进程之中,同一个应用程序之中的不一样的组件之间通信。

用法:继承Binder,而后在service里return
继承Binder用它的对象返回,客户端将bind对象强转成自定义Bind

AIDL

Android interface definition language (android接口定义语言) , 用来跨进程的访问方法。

aidl操做步骤:
1.在两个项目中新建普通文件(new ->General->File),后缀名改为(aidl),客户端和服务端中这个文件所在的包名要保持一致,内容也要同样
编译以后, 会在gen目录下,自动产生同名的,后缀为 Java 的文件。里面有咱们要用到的 Stub类。

public static abstract class Stub extends android.os.Binder implements com.example.aidl.AidlFunctions

2.在接口文件AIDLFunctions.aidl中,咱们定义一个方法 show

interface AidlFunctions{
    void show();
}

3.AIDL的使用,须要一个Service配合,因此咱们在服务端还要声明一个Service

public class AIDLService extends Service {
//stub就是系统自动产生的
    AidlFunctions.Stub binder;

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        binder = new AidlFunctions.Stub() {

            @Override
            //这里是咱们在接口中声明的方法的实现
            public void show() throws RemoteException {
                // TODO Auto-generated method stub
                System.out.println("--------------------收到----------------------");
            }
        };
        return binder;
    }   
}

4.客户端:

//绑定服务,要用到ServiceConnection 
private ServiceConnection serviceConnection;
//自定义的接口,和服务端同样
private AidlFunctions aidlFunctions;

serviceConnection = new ServiceConnection() {

    @Override
    public void onServiceDisconnected(ComponentName name) {
        System.out.println("--------------------ServiceDisconnected----------------------");
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        System.out.println("--------------------ServiceConnected----------------------");
        aidlFunctions = AidlFunctions.Stub.asInterface(service);
    }
};
Intent intent = new Intent("com.example.androidaidl.AIDLService");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
//调用show方法
try {
    aidlFunctions.show();
} catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

使用多进程显而易见的好处就是分担主进程的内存压力。咱们的应用越作越大,内存愈来愈多,将一些独立的组件放到不一样的进程,它就不占用主进程的内存空间了。固然还有其余好处,有些应用后台是有多个进程的,启动一个不可见的轻量级私有进程,在后台收发消息,或者作一些耗时的事情,或者开机启动这个进程,而后作监听等。还有就是防止主进程被杀守护进程,守护进程和主进程之间相互监视,有一方被杀就从新启动它。由于它们要常驻后台,特别是即时通信或者社交应用。

本文地址:https://www.linuxprobe.com/android-strude-mulit.html

相关文章
相关标签/搜索