Android探索:六种IPC方式(上)——Bundle、文件共享、Messenger

Android探索:六种IPC方式(上)——Bundle、文件共享、Messenger

引言

我们了解完Android IPC基础,接下来学习Android中的六种IPC方式:Bundle、文件共享、AIDL、Messenger、ContentProvider、Socket。

注意:本文代码均为kotlin语言

1、Bundle

Android四大组件中的Activity、Service、Receiver都是支持在Intent中传递Bundle数据的,例如在开发中,Activity界面跳转我们经常会使用intent.putExtra(name,value) 来设置数据,从源码来看其实是把值赋给了一个Bundle对象。Bundle像是一个Map集合,但它只能存储序列化的对象,比如基本数据类型、实现了Parcel able或Serializable接口的对象等。组件之间通过这种通讯方式最为简单。

2、文件共享

文件共享就是两个进程间通过读/写同一个文件来交换数据。注意这两个进程 操作的对象不会是同一个,只是内容一样。使用这种方式有个缺点,如果进程的读写并发操作的话,可能会导致数据不同步甚至丢失数据。我们知道SharedPreferences是Android提供的一种轻量级存储方案,也是数据文件操作的一种,不建议具有并发性的进程使用此类方式。

3、Messenger

在Message对象中放入要传递的对象,通过Messenger(信使)就可以在进程间传递Message对象了。其底层实现就是AIDL,由于它一次处理一个请求,因此在服务端不存在并发执行的情形。使用方法也比较简单,下面来看一个简单的例子:客户端把消息传递给服务端。

/**
 * 服务端
 */
class MessengerService : Service() {
    /**
     * 2、将Handler与Messenger绑定
     */
    private val mMessenger = Messenger(MessengerHandler())

    override fun onBind(intent: Intent?): IBinder {
        // 3、返回Messenger对象中的Binder
        return mMessenger.binder
    }

    /**
     * 1、定义一个Handler内部类用来处理收到的信息
     */
    inner class MessengerHandler : Handler(){
        override fun handleMessage(msg: Message?) {
            if (msg!!.what == 0x123){
                Log.e("--------","来自客户端:${msg.data["msg"]}")
            }
            super.handleMessage(msg)
        }
    }
}

注册service

<service android:name=".messenger.MessengerService"
            android:process=":remote"/>
/**
 * 客户端
 */
class MessengerActivity : Activity(){

    /**
     * 1、定义ServiceConnection 链接回掉
     */
    private val mConnection = object : ServiceConnection{
        override fun onServiceDisconnected(name: ComponentName?) {
            Log.e("------","服务已断开")
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            // 2、将Binder 封装给Messenger对象
            val service = Messenger(service)
            val msg = Message.obtain(null,0x123)
            val data = Bundle()
            data.putString("msg","你好,我是客户端")
            msg.data = data
            try {
                // 3、向服务端发送信息
                service.send(msg)
            }catch (e: RemoteException){
                e.printStackTrace()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 4、绑定服务
        val intent = Intent(this,MessengerService::class.java)
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE)
    }

    override fun onDestroy() {
        unbindService(mConnection)
        super.onDestroy()
    }
}

上面的例子演示了服务端如何接受客户端的消息,但是有时候我们还需要服务端向客户端回复结果,如何实现呢,下面我们接着修改上面的例子。先看看 服务端的修改:

override fun handleMessage(msg: Message?) {
            if (msg!!.what == 0x123){// 0x123是消息标识,代表来自客户端的消息,可随意指定
                Log.e("--------","来自客户端:${msg.data["msg"]}")
                // 收到消息后,立即回应客户端
                val client = msg.replyTo
                val replyMsg = Message.obtain(null,0x124)// 0x124是消息标识,代表来自服务端的消息,可随意指定
                val bundle = Bundle()
                bundle.putString("reply","哈哈,我收到你的消息了")
                replyMsg.data = bundle
                try {
                    client.send(replyMsg)// 向客户端发送消息
                } catch (e: RemoteException) {
                    e.printStackTrace()
                }
                return
            }
            super.handleMessage(msg)
        }

然后,客户端准备一个接收消息的Messenger和Handler,并将Messenger发送给服务端

private val mGetServiceMessenger = Messenger(MessengerHandler())

...省略部分代码
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            // 2、将Binder 封装给Messenger对象
            val service = Messenger(service)
            val msg = Message.obtain(null,0x123)
            val data = Bundle()
            data.putString("msg","你好,我是客户端")
            msg.data = data

            // 注意这一句,为了可以接收到服务端的回应,需要把Messenger对象传递给服务端
            msg.replyTo = mGetServiceMessenger

            try {
                // 3、向服务端发送信息
                service.send(msg)
            }catch (e: RemoteException){
                e.printStackTrace()
            }
        }
...

inner class MessengerHandler : Handler(){
        override fun handleMessage(msg: Message?) {
            if (msg!!.what == 0x124){// 0x124代表来自服务端
                Log.e("------","来自服务端:${msg.data["reply"]}")
                return
            }
            super.handleMessage(msg)
        }
    }

运行程序,可以看到Log

扫描二维码关注公众号,回复: 8589629 查看本文章
05-12 02:32:44.145 4357-4357/com.sange.ipc:remote E/--------: 来自客户端:你好,我是客户端
05-12 02:32:44.172 4320-4320/com.sange.ipc E/------: 来自服务端:哈哈,我收到你的消息了

Messenger的使用比较简单,下图是上述例子的工作原理
Messenger工作原理

两个APP如何通讯

上述例子同一APP中的进程间的通讯,其实 和两个APP通讯原理是一样的,这一点要明白,下面讲下两个APP如何通讯
新建一个APP module,名字叫Service。
将上个例子中的MessengerService文件拷贝进来。
这里写图片描述

注册 AndroidManifest.xml

<service android:name="com.sange.service.MessengerService"
            android:enabled="true"
            android:exported="true">
            <!--android:exported属性表示是否可被外部的App绑定,true为允许,false为不允许-->
            <intent-filter>
                <action android:name="com.sange.service.MessengerService"/>
            </intent-filter>
        </service>

在客户端APP 绑定service

// 4、绑定服务
        val intent = Intent()
        // 注意一定要写包名,然后是action名字
        intent.setClassName("com.sange.service","com.sange.service.MessengerService")
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE)

不写包名,会报以下类似错误

05-12 03:18:24.358 6752-6752/com.sange.ipc E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.sange.ipc, PID: 6752
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sange.ipc/com.sange.ipc.messenger.MessengerActivity}: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.sange.service.MessengerService }
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

由于篇幅较长,另外三种 下篇分析。

发布了63 篇原创文章 · 获赞 67 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/sange77/article/details/80212394