看代碼直接到最后,不過建議從頭開始看
一. 起因(廢話)
參加了一個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(觀察者)——物件行為型模式)
1.為什么要使用觀察者模式
安卓系統在開發中被分割為一些列相互協作的,Activity/Fragment,需要維護相關物件的一致性,我們不希望萎了維護一致性而使各個Activity/Fragment緊密耦合,這增加了開發維護的難度,舉個例子,一個區分普通用戶和會員的app,其功能對非付費用戶閹割,如果付費用戶恰好會員過期了,就需要及時通知所有的Activity/Fragment頁面更改顯示,雖然可以通過強制關閉應用重啟,但這樣對用戶體驗極差,各個Activity/Fragment可以作為觀察者,等待資訊的更改,
2.觀察者模式適用以下場景:
1. 當一個抽象模型有兩個方面,其中一個方面依賴于另一方面,將這兩者封裝在獨立的物件中以使它們可以各自獨立地改變和復用,
2. 當一個物件的改變需要同時改變其他物件,而不知道具體又多少物件有待改變,
3. 當一個獨享必須通知其他物件,而它又不能假定其他物件是誰,換言之,你不希望這些物件是緊密耦合的,
在應用層面,把一個個Activity/Fragment看作是一個個物件,顯然其符合第三適用場景,
3.簡易觀察者模式:

Subject(目標)
——目標知道它的觀察者,可以有任意多個觀察者觀察同一個目標
——提供注冊和洗掉觀察者物件的介面
Observer(觀察者)
——為那些在目標發生改變時需要獲得通知的物件定義一個更新介面
ConcreteSubject(具體目標)
——將有關狀態存入各個ConcreteObserver物件
——當它的狀態發生改變時,向它的各個觀察者發出通知
ConcreteObserver(具體觀察者)
——維護一個指向ConcreteSubject物件的參考
——存盤有關狀態,這些狀態應與目標的狀態保持一致
——實作Observer的更新介面以使自身狀態和目標的狀態保持一致
4.具體到代碼層面:(實在看不懂原理的可以直接粘貼創建一個專案進行測驗)
//觀察者抽象類
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<Observer>()
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<String>){
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
5.從簡易觀察者模式進化到具有更改管理器的觀察者模式(誰才是觀察目標)
為什么不能讓Activity/Fragment繼承被觀察者來發布訊息
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,至此引入一個單例,更改管理器,作為目標,
設計具有更改管理器的Activity/Fragment間使用的觀察者模式
改抽象類為介面實作
Subject(目標)
——目標知道它的觀察者,可以有任意多個觀察者觀察同一個目標
——提供注冊和洗掉觀察者物件的介面
Observer(觀察者)
——為那些在目標發生改變時需要獲得通知的物件定義一個更新介面
——在向更改管理器注冊觀察者時,應主動查看更改管理器的延遲通知佇列
ChangeManager(更改管理器) 唯一的Subject
——行程中用于資訊傳遞的唯一的目標,是單例
——當接收到目標發來的通知,提醒各個觀察者更新
——維護延遲通知訊息佇列,并在觀察者注冊時,拿延遲訊息對觀察者試探
6. 代碼實作
//觀察者介面
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<Observer>()
//粘性事件鏈表
private val LateMessageList = ArrayList<Any?>()
//對某一個觀察者遍歷粘性事件
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()
}
}
如何在Activity中使用(實體):
//資訊類
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

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/260276.html
標籤:其他
下一篇:二十四、系結服務
