组件通信、线程通信、进程通信,你真的理清了吗?

通信从总体上来看,可以理解为“修改共享区”和“调用”两种。

修改共享区实现通信

修改共享区实现通信就是通过修改公共区的值,让两者都能获取,从而实现两者的信息传递。

同进程不同组件弱通信:ActivityA中新建计算类CalculatorB,在CalculatorB中进行计算,计算结果保存至sharedpreference、保存到数据库、保存到文件中等。在保存后的数据在ActivityA读取刚才保存的数据然后刷洗界面,这就实现了两个组件的信息狡猾,注意,弱通信只有修改,没有通知,所以ActivityA读取的时间和CalculatorB计算完成的时间不好确定。

同组件不同线程弱通信:ActivityA中新开一个线程ThreadC进行计算,在线程ThreadC计算出结果后,保存到ActivityA的成员变量、保存到数据库、保存到sharedpreference、保存到文件中等,保存后的数据在ActivityA中就可以访问到,如下拉刷新一下进行界面刷新,就完成了信息交换,当然刷新的时候子线程可能也没有计算完成。

 

调用

调用的重点是主动通知并调用对方。务必注意两者的区别,修改共享区只是改变了值,但是没有通知或者调用其方法进行下一部操作;调用的重点是调用并携带数据。

同进程不同组件强通信:ActivityA中新建计算类CalculatorB,在CalculatorB中进行计算,计算结果通过回调的方式传给ActivityA并通知其进行刷新。因为是回调通知,所以不存在刷新和计算结束时间对不上的问题。回调也在同一个进程中执行。

同线程不同进程强通信:ActivityA中新开一个线程ThreadC进行计算,在线程ThreadC计算出结果后,通过handler发送消息通知ActivityA进行刷新,此处通过handler进行线程间通信,并且是计算完成后主动通知,不存在时间对不上的问题。

 

有了上面的区分,我们再来深入比较下标题中描述的组件通信、线程通信、进程通信。从后到前是从大到小的关系,一般来讲,不同的应用运行在不同的进程之中,sharedUserId的场景我们这里先不考虑;一个进程中由于要进行界面刷新、耗时计算等不同的操作,又新建不同的线程做对应的处理;更进一步,一个线程如主线程,要进行不同的功能划分又有各种不同的组件如activity、service等。

 

我们依次来说明其中的通信种类:

组件间通信怎么实现:

1、直接依赖  ---  通过初始化或者方法将自身的引用传递过去,有结果后通过引用直接调用自己的方法。如:ActivityA中新建计算类CalculatorB并将自己的引用传递过去,计算完成后通过自己的引用调用自己的方法实现刷新。

2、接口回调  ---  同上,初始化传入接口,通过接口回调自己类中的方法实现刷新。

3、handler  ---  同上,初始化的时候将ActivityA所依附的handler传递到CalculatorB,计算完成后,通过传递过去的handler发送消息,在ActivityA中接收消息并进行刷新

4、广播  ---  在ActivityA中动态注册自定义广播,CalculatorB中计算完成后发送广播,ActivityA收到广播后进行刷新,本地应用内使用本地广播,跨应用使用全局广播

5、观察者模式  ---  在ActivityA中注册观察者,在CalculatorB中计算完成后通过获取被观察者进行传递数据,观察者观察到被观察者改变,在ActivityA中回调update进行刷新

6、原生api  ---  如activity之间的跳转,可以通过startActivityForResult开启,在onActivityResult中获取前一个activity中传回的数据;又或者activity与fragment、fragment与fragment中的通信,可以通过Fragment.setArguments(bundle)方式传递

上面说了这么多方式,那到底我们应该怎么选择使用什么方式呢?深刻理解他们的区别之后就很好选择了

如果是联系非常紧密,相互依赖严重,有谷歌提供的api,就用api;如activity上面依附了fragment,他们进行通信就选择6。如果没有存在的api,如ActivityA与CalculatorB之间,遵循面向接口编程的思想,选择2。3通常用于线程间通信,虽然也可以用做组件间通信,但是相比于2其代码量不占优势,不推荐,这样写的案例也比较少。4广播的方式受影响因素多,手机中的广播太多时会有明显的延时,极端情况下甚至可能收不到。5观察者模式一个修改,多个订阅的观察者都可以收到,适合一个数据更改多个界面刷新的场景,比接口回调一个修改回调一个结果的使用场景更宽泛。一句话总结:有api用api,没api用接口,一处改变多处接收用观察者。

 

线程间通信怎么实现

1、handler  ---  在主线程中初始化handler,在子线程中计算完成后,通过handler发送消息到主线程,进行界面刷新。handler是原生提供的最基础的线程间通信的基础类,是处理异步消息的核心类。主线程handler、子线程hanlder初始化的Loop.prepare、HandlerThread、handler内存泄漏、以及组合handler和Thread的asynctask等问题,参见历史文章

2、广播  ---  在ActivityA中动态注册自定义广播,ThreadC中计算完成后发送广播,ActivityA收到广播后进行刷新。一个应用间线程间使用本地广播优于全局广播

3、观察者模式  ---  在子线程ThreadC中计算完成后通过观察者对象传递数据,再在ActivityA中的观察者回调update中刷新

使用方式的选择:简单一对一的,子线程主线程等这种,直接使用handler;一个修改,多处需要监听到并作出反应的,观察者模式。

 

进程间通信怎么实现

安卓有四大组件,所以AndroidSDK提供了四种夸进程通信的方式 。

Activity通过startActivity时传入包含其他进程Activity的intent实现跳转到其他界面,并可以携带数据;如录制视频结束后跳转到相册界面。

BroadCast通过发送广播实现夸进程,比如应用可以收到息屏广播。

ContentProvider可以跨进程访问其他应用存储的数据,例如通过provider获取设备的音频、视频列表及信息 并可以对其进行增删改查。

Service的跨进程通信是通过AIDL。

Aciivity和ContentProvider跨进程通信场景单一,不适用普通场景,Broadcast受系统影响有延时,所以真正能够实现两个进程间自由翱翔、任意通信的只有AIDL。

 

从上面我们可以看到,观察者模式在组件间、线程间通信时,可以很好的一对一,一对多的通知,而接口回调只能一对一通知;另外,当我们项目更大更复杂、层级结构更加深时,通过接口一层一层调用获取结果后再一层层回调回去就显得不那么好了,这种情况下更突显出观察者模式的好处。项目大,层级深,交互多时,各种情况下都需要观察者,将这些观察者统一起来放到hashMap中进行维护,被观察者变化时通知对应的观察者,这就形成了事件总线框架,其中经典的 就是EventBus。

同样道理,我们开发中级项目时,这种情况也比较多,但是也没有那么多,回调多是一对一时且都在主线程时,也可以将所有的回调接口统一放到hashMap中维护起来,做个简单的事件中心EventCenter。EventCenter框架目前正在自定义优化中。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值