技術學習記錄

[Android]用EventBus實作觀察者模式

觀察者模式是軟體設計模式的一種,分為被觀察者和觀察者。

當被觀察者的狀態發生變化,觀察者就會獲得事件通知並作出處理。

詳細介紹可以參考維基百科

EventBus介紹

EventBus是一個針對Android最佳化的事件發送&訂閱框架,目的是為了簡化各個元件間的通訊。

EventBus主要是由事件、事件訂閱者、事件發布者構成:

  • 事件是指任何要被發送的資料,可以是任意資料型別
  • 事件訂閱者是指接收資料的目標元件
  • 事件發布者是指負責發送資料的元件

EventBus有四種執行緒模式,具體如下:

  • MAIN:事件處理會在主執行緒中執行,如果處理的時間過長,會引起ANR。
  • POSTING:預設的處理模式,表示發送跟接收在同一個執行緒中執行。
  • BACKGROUND:在這個模式下,如果事件是在主執行緒發送,那麼接收者就會建立一個執行緒處理事件。如果事件是在子執行緒發送,那接收者就會在發布者所在的執行緒中處理事件。注意:這個模式下無法進行UI相關的操作!
  • ASYNC:不管事件從哪個執行緒發布,接收端都會在子執行緒處理。注意:這個模式下無法進行UI相關的操作!

用法

這裡使用一個Service作為發送者、一個Activity作為接收者。

Service每一秒發送一個數值+1的事件。當Activity接收到事件後,透過TextView顯示事件的數值,步驟如下:

1.首先在build.gradle加入EventBus套件庫,如下所示:

dependencies {
     implementation 'org.greenrobot:eventbus:3.0.0'
}

2.宣告一個自訂類別,當作EventBus傳遞的參數,如下所示:

data class MyEvent(
    var counter: Int? = null
)

3.建立Service,啟動方式這裡用Bind Service,如下所示:

class MyService : Service() {

    private val mLocalBinder = LocalBinder()

    private var counter = 0

    private val handler = Handler()
    private val timerCounter = object : Runnable {
        override fun run() {
            counter++

            // 發送事件
            EventBus.getDefault().post(
                MyEvent(counter)
            )

            handler.postDelayed(this, 1000)
        }
    }

    override fun onBind(arg0: Intent?): IBinder {
        return mLocalBinder
    }

    override fun onCreate() {
        super.onCreate()
        handler.post(timerCounter)
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onUnbind(intent: Intent?): Boolean {
        return super.onUnbind(intent)
    }

    override fun onDestroy() {
        super.onDestroy()
        handler.removeCallbacks(timerCounter)
    }

    inner class LocalBinder : Binder() {
        val service: MyService = this@MyService
    }
}

4.在Activity實作處理事件的function,並加入啟動Service的程式碼,如下所示:

class MainActivity : AppCompatActivity() {

    private var mService: MyService? = null
    private val mServiceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, serviceBinder: IBinder) {
            mService = (serviceBinder as LocalBinder).service
        }

        override fun onServiceDisconnected(name: ComponentName) {}
    }

    private val eventBus: EventBus by lazy {
        EventBus.getDefault()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mService = null
        val it = Intent(this, MyService::class.java)
        bindService(it, mServiceConnection, BIND_AUTO_CREATE) //綁定Service
    }

    override fun onResume() {
        super.onResume()

        eventBus.register(this)
    }

    override fun onPause() {
        super.onPause()

        eventBus.unregister(this)
    }

    override fun onDestroy() {
        super.onDestroy()

        mService = null
        unbindService(mServiceConnection)
    }

    // 訂閱事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEvent(event: MyEvent) {
        textView.text = "count: ${event.counter}"
    }
}

最後執行應用程式,即可看到TextView上的數值每秒+1。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *