+3

Broadcast Receiver trong Android

1. Broadcast Receiver là gì ?

Broadcast Receiver là một Android component cho phép đăng kí để lắng nghe những sự kiện từ hệ thống hoặc ứng dụng . Tất cả nhưng "receiver" đã được đăng kí đều được thông báo khi sự kiện nó lắng nghe xảy ra vào run-time.

Ví dụ một số Broadcast từ hệ thống như thông báo rút cắm sạc , pin yếu , chế độ máy bay , khởi động máy ,... Không như activity , BroadcastReceiver không có giao diện , ta có thể truyền thông tin thông qua intent để đóng gói dữ liệu.

2. Đăng kí nhận Broadcasts

  1. Đăng kí tĩnh
  • Sử dụng tag <receiver> trong Android Manifest

  • Một vài sự kiện sẽ yêu cầu Permission

  • Từ Android 8.0 (API26) , các ứng dụng đăng kí Implicit intent trong Manifest sẽ không thể nhận được event. Ta phải chuyển qua "Context registration " trong code.

    Tuy nhiên thì vẫn có một số event có thể nhận được https://developer.android.com/guide/components/broadcast-exceptions

<receiver android:name = ".ActionReceiver">
    <intent-filter>
            <action android:name = "android.intent.action.AIRPLANE_MODE"/>
    </intent-filter>
</receiver>
class ActionReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context? , intent: Intent?) {
        // Event received....
    }
}
  • Hiểu như là bất cứ receiver nào có thẻ trong Manifest và có action "android.intent.action.AIRPLANE_MODE" đều sẽ nhận được event.
  1. Đăng kí động

Một cách khác để đăng kí nhận event đó là đăng kí trong code với phương thức Context.registerReceiver() và không quên hủy đăng kí bằng Context.unregisterReceiver()

Đừng quên hủy đăng kí , nếu không hệ thống sẽ báo lỗi "leaked broadcast receiver" , nếu đã đăng kí ở onResume() thì nên hủy đăng kí ở onPause() tránh trường hợp ta sẽ đăng kí nhiều lần . Hoặc đã đăng kí ở onCreate() thì nên hủy ở onDestroy() để tránh rò rỉ broadcast ra ngoài Activity.

Tuy nhiên cũng vì thế mà khi activity bị hủy thì việc lắng nghe Broadcast cũng dừng theo , còn đăng kí qua Manifest thì không.

val intentFilter = IntentFilter("android.intent.action.AIRPLANE_MODE")
registerReceiver(actionReceiver , intentFilter)
override fun onDestroy() {
    super.onStop()
    unregisterReceiver(actionReceiver)
}
  • Vậy thì cách đăng kí nào tốt hơn ?

Tùy vào mục đích của event mà ta sẽ chọn cách đăng kí cho phù hợp

Nếu bạn muốn cập nhật bên ngoài , ngay khi ở màn hình chính và không bật ứng dụng , như thông báo khởi động máy , tắt màn hình ,.. ta có thể chọn cách đăng kí tĩnh

Ngược lại nếu mình muốn chủ động trong việc đăng kí , hủy đăng kí hay để đảm bảo bảo mật thông tin , có thể chọn cách đăng kí động.

3. Gửi Broadcast

  1. Gửi Broadcast thông thường

Đây là cách gửi broadcast không đồng bộ , bên receiver cũng vậy. Các receiver nhận không theo thứ tự và không thể sử dụng kết quả truyền qua nhau.

val intent = Intent("action.myaction")
intent.putExtra("action" , "data")
sendBroadcast(intent)
  1. Gửi broadcast theo thứ tự

Cách gửi này được bên receiver nhận lần lượt theo thứ tự dựa vào thuộc tính android:priority . Receiver nào có chỉ số priority cao hơn sẽ nhận trước và truyền data tới receiver tiếp theo hoặc có thể hủy luôn chuỗi broadcast.

val intent = Intent("action.myaction")
val bundle = Bundle()
bundle.putString("action" , "data")
sendOrderedBroadcast(intent , null , object : BroadcastReceiver() {
    override fun onReceive(context: Context? , intent: Intent?) {
        // get final data....
        val finalData = getResultExtras(true).getSString("action")
        Log.d(TAG , "Final data : $finalData")
    }
} , null , REQUEST_CODE , null , bundle)
<receiver android:name = ".ActionReceiver2">
    <intent-filter android:priority = 2>
        <action android:name = "action.myaction"/>
    </intent-filter>
</receiver>
val intentFilter = IntentFIlter("action.myaction")
intentFilter.priority = 1
registerReceiver(actionReceiver , intentFilter)
 : 2 - data
 : 1 - data
 : Final data : data

4. LocalBroadcastManager

Khi đăng kí Broadcast thông thường thì các ứng dụng có đăng kí event đều có thể nhận đươc. LocalBroadcastManager giúp chúng ta có thể bảo mật những thông tin và chỉ có thể gửi trong nội bộ ứng dụng.

LocalBroadcastManager.getInstance(this).registerReceiver(object: BroadcastReceiver() {
    override fun onReceive(context: Context? , intent: Intent?) {
        val data = intent.getStringExtra("data")
    }
} , IntentFilter("My local broadcast manager")
val intent = Intent("My local broadcast manager")
intent.putExtra("data" , "my data")
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)

5. Bảo mật Broadcast với permission

Bên gửi Broadcast có thể kiểm soát được bên nhận nào sẽ nhận được bản tin bằng cách gửi kèm theo một permission.

sendBroadcast(Intent("action.myaction") , Manifest.permission.SEND_SMS)

Và để nhận được Broadcast thì ứng dụng phải xin cấp quyền <uses-permission android:name="android.permission.SEND_SMS"/>

Đối với cách đăng kí thẻ trong Manifest thì ta sẽ set thêm thuộc tính android:permission trong thẻ <receiver>

 <receiver android:name=".ActionReceiver"
          android:permission="android.permission.SEND_SMS">
    <intent-filter>
        <action android:name="android.intent.action.AIRPLANE_MODE"/>
    </intent-filter>
</receiver>

Nếu chúng ta không muốn nhận Broadcast từ bên ngoài phạm vi ứng dụng , ta set thêm thuộc tính android:exported attribute = false

Còn đối với cách đăng kí bằng Context registration :

val filter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)
registerReceiver(actionReceiver, filter, Manifest.permission.SEND_SMS, null)

All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.