参加了一个android程序员招聘的面试,被问到广播相关的内容,我根据工作经验,做出了一些画蛇添足的回答(不一定对):
广播可以作为进程之间的通信,也可以在Activity/Fragment之间传递内容。但是鉴于Activity/Fragment之间传递内容的各个方法都有比较明显的缺点。
1. 比如Bundle无法传递大容量数据,且传递复杂信息操作繁琐;
2. Handler回产生一个队列,且如果需要重绘UI会有线程之间切换带来的比较难以控制的效果;
3. 接口好使但比较难写(对于我来说,经验不足);
4. 使用Application传递消息在用户翻转,切换的时候,可能会导致内存泄露(这点不确定,没用过);
5. 单例的话,项目禁止使用,用的多了,会产生一些奇怪的单例,毕竟下次维护可能得半年后了;
6. 通过永固化存储虽然完全解决了对象复杂度的问题,但是其需要通过I/O速度太慢了。
所以原来组里通常使用EventBus来传递信息,因为它完成了Acticity之间的解耦。
面试官突然来了兴趣,问道:“EventBus的源码有钻研过吗?”
好家伙,我直接好家伙。我就去应聘个一年工作经历的android码农,居然问我源码。说实在的,我感觉如果我能扯出点什么说不定会给我发个Offer。可惜没有如果。
回头看了好几天的源码,横竖睡不着,满眼都是注解框架,回调。细细琢磨,字里行间写着再来过。
But,天无绝人之路,还是能够搜到EventBus用的是 观察者模式 。掏出大学时期买来却从没看过的《设计模式》一顿翻阅,决定自己写一个类似功能的,省的下次面试被问到说不出什么内容。
(1. 2. 3.抄书,有书自己看,《设计模式 可复用面对对象软件的基础 机械工业出版社》 第五章 行为模式 OBSERVER(观察者)——对象行为型模式)
安卓系统在开发中被分割为一些列相互协作的,Activity/Fragment。需要维护相关对象的一致性。我们不希望萎了维护一致性而使各个Activity/Fragment紧密耦合,这增加了开发维护的难度。举个例子,一个区分普通用户和会员的app,其功能对非付费用户阉割,如果付费用户恰好会员过期了,就需要及时通知所有的Activity/Fragment页面更改显示,虽然可以通过强制关闭应用重启,但这样对用户体验极差。各个Activity/Fragment可以作为观察者,等待信息的更改。
1. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这两者封装在独立的对象中以使它们可以各自独立地改变和复用。
2. 当一个对象的改变需要同时改变其他对象,而不知道具体又多少对象有待改变。
3. 当一个独享必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的。
在应用层面,把一个个Activity/Fragment看作是一个个对象,显然其符合第三适用场景。
Subject(目标)
——目标知道它的观察者。可以有任意多个观察者观察同一个目标
——提供注册和删除观察者对象的接口
Observer(观察者)
——为那些在目标发生改变时需要获得通知的对象定义一个更新接口
ConcreteSubject(具体目标)
——将有关状态存入各个ConcreteObserver对象
——当它的状态发生改变时,向它的各个观察者发出通知
ConcreteObserver(具体观察者)
——维护一个指向ConcreteSubject对象的引用
——存储有关状态,这些状态应与目标的状态保持一致
——实现Observer的更新接口以使自身状态和目标的状态保持一致
//观察者抽象类
abstract class Observer {
abstract fun Update(msg:Any?)
}
//被观察者抽象类
abstract class Subject {
abstract fun Attach(observer: Observer)
abstract fun Detach(observer:Observer)
abstract fun Notify(msg:Any?)
}
//以下是随便定义的实体观察者和被观察者
//一号观察者,对类型为Message的对象有特殊处理,否则直接打印
class FirstObserver : Observer() {
override fun Update(msg: Any?) {
if(msg is Message){
println("1号观察者收到Message消息,编号为"+msg.num+"内容为"+msg.msg )
}else{
println("1号观察者收到消息:内容======"+msg.toString())
}
}
}
//二号观察者,无论如何直接打印
class SecondObserver : Observer() {
override fun Update(msg: Any?) {
println("2号观察者收到消息:内容======"+msg.toString())
}
}
//目标实体
class FirstSubject : Subject() {
//存放观察者
private var observers = ArrayList()
override fun Attach(observer: Observer) {
observers.add(observer)
}
override fun Detach(observer: Observer) {
observers.remove(observer)
}
override fun Notify(msg:Any?) {
for (observe in observers){
observe.Update(msg)
}
}
}
//Message类,在一号观察者中有特殊处理
class Message(var msg:String,var num:Int)
//实际测试代码
fun main(args: Array){
val firstSubject = FirstSubject()//被观察者实体
val firstObserver = FirstObserver()//一号观察者
val secondObserver = SecondObserver()//二号观察者
firstSubject.Attach(firstObserver)//一号观察者订阅被观察者
firstSubject.Attach(secondObserver)//二号观察者订阅被观察者
firstSubject.Notify("来一份通知")//被观察者发送String信息
firstSubject.Notify(123)//被观察者发送Int信息
val msg = Message("说话",2)//被观察者发送Message对象信息
firstSubject.Notify(msg)
firstSubject.Detach(firstObserver)//撤销二号观察者对被观察者的查看
firstSubject.Notify(null)//被观察者发送空
}
//测试结果
1号观察者收到消息:内容======来一份通知
2号观察者收到消息:内容======来一份通知
1号观察者收到消息:内容======123
2号观察者收到消息:内容======123
1号观察者收到Message消息,编号为2内容为说话
2号观察者收到消息:内容======com.example.eventbusapplication.example.Message@7e0ea639
2号观察者收到消息:内容======null
1. 在使用kotlin开发的时候第一个问题就是我们的Activity/Fragment是继承自安卓系统的Activity/Fragment的,只有继承了Activity/Fragment才能被认作是Activity/Fragment,由于kotlin和JAVA的单继承特性,是不能直接使用抽象类的方式进行继承。
2. 考虑实际开发过程中,各个Activity/Fragment之间是平级的,只有人为规定其为主Activity/Fragment或者起始Activity/Fragment才会有所区别。所以并不存在某一被观察Activity/Fragment知晓其观察者Activity/Fragment。破坏了"目标知道它的观察者。可以有任意多个观察者观察同一个目标"这一条件。
3. 在开发过程中,比如需要向后一Activity/Fragment传递一个信息,那么本Activity/Fragment作为观察对象没有很好的办法提前知道后一Activity/Fragment是什么,甚至后一Activity/Fragment不一定存在。破坏了“目标提供注册和删除观察者对象的接口”这一条件。
综上所述,目标必不能是一个Activity/Fragment;而观察者应该是一个Activity/Fragment。至此引入一个单例,更改管理器,作为目标。
改抽象类为接口实现
Subject(目标)
——目标知道它的观察者。可以有任意多个观察者观察同一个目标
——提供注册和删除观察者对象的接口
Observer(观察者)
——为那些在目标发生改变时需要获得通知的对象定义一个更新接口
——在向更改管理器注册观察者时,应主动查看更改管理器的延迟通知队列
ChangeManager(更改管理器) 唯一的Subject
——进程中用于信息传递的唯一的目标,是单例
——当接收到目标发来的通知,提醒各个观察者更新
——维护延迟通知消息队列,并在观察者注册时,拿延迟消息对观察者试探
//观察者接口
interface Subject {
fun Notify(msg:Any?)
fun LateNotify(msg:Any?)
fun Attach(observer: Observer)
fun Detach(observer:Observer)
}
//观察者接口
interface Observer {
fun Update(msg:Any?)
}
//唯一的观察对象
class ChangeManager:Subject {
//观察者链表
private val ObserverList = ArrayList()
//粘性事件链表
private val LateMessageList = ArrayList()
//对某一个观察者遍历粘性事件
fun checkLateMessageList(observer: Observer){
for (latemessage in LateMessageList){
observer.Update(latemessage)
}
}
//添加粘性事件
private fun addLateMessage (lateMessage: Any?){
LateMessageList.add(lateMessage)
}
//添加粘性事件(对外抽象)
override fun LateNotify(msg: Any?) {
addLateMessage(msg)
}
//粘性事件需要手动解除,这点和EventBus是一样的
fun removeLateMessage(lateMessage: Any?){
LateMessageList.remove(lateMessage)
}
//通知所有观察者更新信息
override fun Notify(msg: Any?) {
for (observer in ObserverList){
observer.Update(msg)
}
}
//注册新的观察者
override fun Attach(observer: Observer) {
checkLateMessageList(observer)
ObserverList.add(observer)
}
//注销某个观察者
override fun Detach(observer: Observer) {
ObserverList.remove(observer)
}
}
//个性化一个Application,在里面单例化一个ChangeManager
class MyApp : Application() {
companion object{
var instance:MyApp by Delegates.notNull()
var changeManager: ChangeManager by Delegates.notNull()
}
override fun onCreate() {
super.onCreate()
instance = this
changeManager = ChangeManager()
}
}
//信息类
class EventMessage (var num:Int, var str:String)
//第一个Activity
class FirstActivity : AppCompatActivity(), Observer {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_first)
MyApp.changeManager.Attach(this)
btn_first.setOnClickListener {
//发布粘性事件
MyApp.changeManager.LateNotify("来试试")
val intent = Intent(this,SecondActivity().javaClass)
startActivity(intent)
}
}
override fun Update(msg: Any?) {
if(msg is EventMessage) {
Log.i("tofu", "FirstActivity收到了Message对象的消息,消息内容为===${msg.num}===${msg.str}")
} else{
Log.i("tofu", "FirstActivity收到了其他消息")
}
}
}
//第二个Activity
class SecondActivity : AppCompatActivity(),Observer {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
//注册监听(观察者)
MyApp.changeManager.Attach(this)
btn_second.setOnClickListener {
val intent = Intent(this,ThirdActivity().javaClass)
startActivity(intent)
}
}
//观察者更新的事
override fun Update(msg: Any?) {
Log.i("tofu", "SecondActivity收到了信息")
}
}
//第三个Activity
class ThirdActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_third)
MyApp.changeManager.Notify(EventMessage(11,"来,更新"))
}
}
///
//第一第二个Activity各自有一个按钮跳转到下一个Activity
//结果
I/tofu: SecondActivity收到了信息
I/tofu: FirstActivity收到了Message对象的消息,消息内容为===11===来,更新
I/tofu: SecondActivity收到了信息
重点使用了观察者模式 和 单例模式 两种重要的设计模式。与一般观察者模式用法不一样的是,对于在Activity/Fragment间传递信息的观察者模式,只有一个被观察者,且不是某一个Activity/Fragment。
显然在实例中可以看出,远不如原版的EventBus,比方说,需要手动在Update中判定msg对象是什么类型。
手写不易,如果有帮助转载标明:https://blog.csdn.net/zxy7311074/article/details/113803571。欢迎大佬指正
感谢大佬指正,欢迎进开发交流群讨论问题:200409033