解鎖管理EventBus註冊新姿式——自定義註解+反射

8B40D4E0-C581-43E0-860A-6C9082052E41_1_201_a.jpeg

解鎖管理EventBus註冊新姿式——自定義註解+反射

開局一張圖,裝備全靠撿
本文旨在分享code生涯當中的一些小技術java

EventBus簡介

官網對EventBus的介紹
EventBus is an open-source library for Android and Java using the publisher/subscriber pattern for loose coupling. EventBus enables central communication to decoupled classes with just a few lines of code – simplifying the code, removing dependencies, and speeding up app development.面試

翻譯過來就是:
EventBus是一個Android和Java的開源庫,使用發佈者/訂閱者模式進行鬆散耦合。EventBus使中央通訊可以僅用幾行代碼解耦類——簡化代碼,減小依賴項,並加快應用程序開發。markdown

從介紹中咱們能夠了解到這是一個事件發佈/訂閱框架架構

使用EventBus有什麼好處?app

  • 簡化組件之間的通訊
  • 事件發送方和接收方解耦
  • 可以很好地使用UI組件(例如Activities, Fragments)和後臺線程
  • 避免複雜且容易出錯的依賴關係和生命週期問題
  • 速度快;專門爲高性能而優化
  • 很小(~60k jar)
  • 實際安裝量超過10,000,000個的應用程序證實了這一點
  • 具備切換線程、訂閱者優先級等高級功能

EventBus自2012-07由greenrobot發佈第一個版本,歷經7年之久,現版本已更新至3.2。從事Android開發的夥伴就算沒用過也必定據說過這個框架,由於它實在是太普及了。儘管目前也有許多新的事件總線框架出現,可是依舊阻擋不住我對它的熱愛,做爲經典的觀察者模式實現,以及在Android平臺的普及度,它也深受面試官們寵愛。框架

EventBus簡單使用

這裏不做EventBus的全面解析,只羅列下簡單的使用,想必你們對於EventBus的使用已是倒背如流了,可是這裏仍是要水一下ide

註冊與解除註冊

使用該框架進行事件的發佈須要進行註冊,再也不使用時須要進行解除註冊工具

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 註冊成爲訂閱者
        EventBus.getDefault().register(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        // 解除註冊 再也不接收事件
        EventBus.getDefault().unregister(this)
    }
}
複製代碼

發佈事件

/** * 自定義的事件類 * * @property message String 消息 * * @author Qu Yunshuo * @since 3/29/21 8:05 PM */
data class SimpleEvent(val message: String)

/** * 發佈一個事件 */
fun postEvent() {
    EventBus.getDefault().post(SimpleEvent("Hello EventBus!"))
}
複製代碼

綁定接受事件的方法

/** * 經過[Subscribe]註解進行註冊,而且能夠指定[ThreadMode]該方法執行的線程類型 */
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(event: SimpleEvent) {
    Log.d("qqq", "onEvent: ${event.message}")
}
複製代碼

使用自定義註解管理EventBus註冊

至此就是發佈與訂閱的簡單實用,更詳細的使用在這裏就不詳細說明,不是本文的重點。
到這裏就能發現,咱們每一個訂閱者都須要進行手動的註冊與解除註冊,不然會產生異常。
那最理想的狀態就是不用每一次都手動的註冊與解除註冊,而是可以自動完成。oop

常見封裝方式:

/** * 最多見的方式就是寫在基類中,在[onCreate]方法中進行註冊,在[onDestroy]方法中進行解除註冊 * 這樣實現類就能夠自動的完成註冊與解除註冊,徹底不用考慮忘記解除註冊這種低級錯誤🙅 */
open class BaseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        EventBus.getDefault().register(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        EventBus.getDefault().unregister(this)
    }
}
複製代碼

這種方式簡單粗暴有效,可是弊端也很明顯,無論子類需不須要註冊都會自動幫你註冊完,簡直快樂的一批,固然這不是咱們想要的效果。
那其實能夠在這種方式上進行優化,好比寫一個hook方法,讓子類重寫決定是否進行初始化,這也是一個不錯的方案。組件化

open class BaseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 判斷子類是否須要進行註冊和解除註冊
        if (isRegisterEventBus()) EventBus.getDefault().register(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        // 判斷子類是否須要進行註冊和解除註冊
        if (isRegisterEventBus()) EventBus.getDefault().unregister(this)
    }

    /** * 是否註冊EventBus * @return Boolean */
    open fun isRegisterEventBus(): Boolean = false
}
複製代碼

這也是一個不錯的方案,讓子類決定是否進行註冊,避免一刀切所有註冊的狀況,代價只是多重寫一個方法。下面介紹另一種方案,使用自定義註解+反射。

自定義註解+反射

總體思路就是咱們自定義一個註解,在須要進行註冊的類上添加註解,在基類裏進行判斷當前子類是否使用了該註解從而決定是否進行註冊

/** * 進行標記須要進行註冊EventBus * * @author Qu Yunshuo * @since 3/29/21 8:33 PM */
@Target(AnnotationTarget.CLASS)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
annotation class EventBusRegister


/** * Activity基類 * * @author Qu Yunshuo * @since 3/29/21 8:36 PM */
open class BaseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 獲取到Class對象判斷是否有EventBusRegister註解
        if (javaClass.isAnnotationPresent(EventBusRegister::class.java)) {
            EventBus.getDefault().register(this)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        // 獲取到Class對象判斷是否有EventBusRegister註解
        if (javaClass.isAnnotationPresent(EventBusRegister::class.java)) {
            EventBus.getDefault().unregister(this)
        }
    }
}
複製代碼

以上是註解和基類的邏輯,十分的簡單,須要註冊時,只須要在添加該註解就ok

@EventBusRegister
class MainActivity : BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {...}
}
複製代碼

是否是使用起來也是十分的簡單,並非說這種方案是最優的,本文只是介紹經過自定義註解+反射來實現封裝EventBus註冊的邏輯,get到之後就能夠進行觸類旁通。

簡單封裝Utils

下面也放上簡單封裝的EventBus工具類

/** * EventBus工具類 * * @author Qu Yunshuo * @since 3/29/21 8:42 PM */
object EventBusUtils {

    /** * 訂閱 * @param subscriber 訂閱者 */
    fun register(subscriber: Any) = EventBus.getDefault().register(subscriber)

    /** * 解除註冊 * @param subscriber 訂閱者 */
    fun unRegister(subscriber: Any) = EventBus.getDefault().unregister(subscriber)

    /** * 發送普通事件 * @param event 事件 */
    fun postEvent(event: Any) = EventBus.getDefault().post(event)

    /** * 發送粘性事件 * @param stickyEvent 粘性事件 */
    fun postStickyEvent(stickyEvent: Any) = EventBus.getDefault().postSticky(stickyEvent)

    /** * 手動獲取粘性事件 * @param stickyEventType 粘性事件 * @param <T> 事件泛型 * @return 返回給定事件類型的最近粘性事件 */
    fun <T> getStickyEvent(stickyEventType: Class<T>): T = EventBus.getDefault().getStickyEvent(stickyEventType)

    /** * 手動刪除粘性事件 * @param stickyEventType 粘性事件 * @param <T> 事件泛型 * @return 返回給定事件類型的最近粘性事件 */
    fun <T> removeStickyEvent(stickyEventType: Class<T>): T = EventBus.getDefault().removeStickyEvent(stickyEventType)
}
複製代碼

結語

其實核心代碼就那麼幾行,大多數開發者在平常工做中都沒有用過自定義註解,本文借EventBus向你們展現了自定義註解+反射進行初始化的一個操做,其實仍是十分的簡單的。
技巧都是慢慢積累起來的,也許之後的開發過程當中,就能夠用這種方式去解決一些問題,這也是我一年前看博客發現的一個操做,當時我還在實習,內心想着居然還有這種騷操做,從此一直到如今我都將這讓種方法沿用至今,今天拿出來水了一篇,也是想分享下這個小技巧。
code 不僅是工做,也會是熱愛
另外有興趣的能夠看一下我剛畢業時寫的第一篇文章:一個 Android MVVM 組件化架構框架

相關文章
相關標籤/搜索