Tất tần tật về Broadcast Receiver trong Android

Bạn đã khi nào biết tới “đài phát thanh truyền hình” trong Android chưa?  Nếu chưa thì mình tiết lộ nhé! Đó chính là Broadcast Receiver. Vậy broadcast receiver android là gì? Đúng như cái tên của nó, bổ phận chính của Broadcast receiver trong android là lan truyền thông tin trong hệ thống & chỉ những áp dụng đăng kí mới thu được.

Nội dung này mình sẽ chia sẻ toàn bộ những tri thức trọng yếu nhất về Broadcast Receiver Android.

Từ đó bạn có thể đơn giản áp dụng & sử dụng hiệu quả cho áp dụng của mình

1. Broadcast Receiver Android là gì?

Android Broadcast Receiver là một thành phần nơi bạn có thể đăng ký buổi lễ của hệ thống hay áp dụng. Bạn sẽ thu được nhắc nhở về các buổi lễ đã đăng ký trước đây. Việc phát tin broadcast có thể xuất phát điểm từ hệ thống hoặc từ các áp dụng

Chẳng hạn: một số broadcast từ hệ thống như nhắc nhở pin yếu, bật tắt màn hình, connect hay ngắt kết thiết bị ngoại vi…

Với cấp độ áp dụng có thể kể ra như khi bạn download một file nhạc. Áp dụng nhạc này sẽ thu được nhắc nhở về việc download, sau thời điểm chấm dứt sẽ mang bài hát này vào danh mục để bật. Để thực hiện được việc này, áp dụng nhạc thiết yếu phải đăng ký cho buổi lễ.

Không giống như Activity, Broadcast receiver trong android chẳng hề có giao diện người dùng. Mặc dầu nó có thể tạo nhắc nhở trên thanh status bar.

Để truyền thông tin, Broadcast receiver sử dụng Intent để đóng gói dữ liệu. Nếu bạn đã đọc nội dung của mình về Intent trong Android thì sẽ đơn giản hiểu về Broadcast receiver trong Android.

Nội dung này mình sẽ chăm chú 3 vấn đề chính:

  • Cách tạo Broadcast Receiver
  • Chỉ dẫn đăng kí để nhận nhắc nhở từ Broadcast Receiver
  • Cách gửi Broadcast Sự kiện/Intent
  • Vấn đề bảo mật khi sử dụng Broadcast Receiver

2. Tạo một class Broadcast Receiver trong Android

Hãy theo dõi đoạn code bên dưới để xem cách tạo một broadcast receiver trong Android như nào:

class MyReceiver:BroadcastReceiver() {
  fun onReceive(context:Context, intent:Intent) {
    // This method is called when this BroadcastReceiver receives an Intent broadcast.
    Toast.makeText(context, "Action: " + intent.getAction(), Toast.LENGTH_SHORT).show()
  }
}

Tất cả chúng ta sẽ tạo một class là MyReciever & được kế thừa từ BroadcastReceiver. Do BroadcastReceiver là một abstract class nên tất cả chúng ta bắt buộc phải override hàm onReceiver(). Bất kể bao giờ có một buổi lễ xảy ra, Android sẽ gọi hàm onReceiver().

Bạn để mắt rằng, hàm onReceiver() có 2 tham số được truyền vào là: Intent & Content. Với Intent, bạn sẽ thu được những thông tin thiết yếu từ hệ thống.

Xem Thêm  A Tuple trong Python là gì - tuple nghĩa trong python

Còn Context sẽ giúp bạn có thể làm được một việc như start một Activity hay Service kiểu như context.startService(new Intent(this, TestService.class));

3. Đăng kí nhận Broadcast Receiver trong Android

Tất cả chúng ta đã giải quyết việc tạo một Broadcast Receiver trong Android, nhưng để nó có thể thu được nhắc nhở từ hệ thống hay áp dụng khác thì nó cần phải đăng kí. Có 2 cách đăng kí:

  • Đăng kí bằng cách khai báo trong Manifest file
  • Hoặc đăng kí bằng Kotlin code

#Cách 1: Đăng kí Broadcast Receiver trong Manifest File

Đây là cách có vẻ là dễ nhất

<receiver
    android_name="com.pycitup.pyc.MyReceiver"
    android_enabled="true"
    android_exported="true" >
    <intent-filtervàgt;
        <action android_name="com.pycitup.BroadcastReceiver" />
    </intent-filtervàgt;
</receivervàgt;

Tất cả chúng ta sử dụng thẻ <receivervàgt;để đăng kí với một intent filter.

Nếu bạn quên chưa biết Intent filter là gì thì mời độc giả lại nội dung về intent này nhé: Intent trong Android: Vai trò & cách dùng

Về căn bản có thể hiểu nôm na: Áp dụng sử dụng intent filter để nhắc nhở với hệ thống là áp dụng của tôi đăng kí nhận nhắc nhở.

Nhưng không phải nhận toàn bộ mà chỉ những nhắc nhở nào thích hợp thì mới nhận. Bước này thì chỉ những nhắc nhở nào có action là: com.pycitup.BroadcastReceiverthì mới thu được

#Cách 2: Sử dụng code để đăng kí Broadcast Receiver

Tất cả chúng ta có thể thực hiện việc đăng kí bằng code Kotlin như sau:

var filter = IntentFilter("com.pycitup.BroadcastReceiver")
var myReceiver = MyReceiver()
fun registerReceiver(myReceiver, filter)

Cũng giống như cách đăng kí bằng cách khai báo trong Manifest. Tất cả chúng ta cũng chỉ đăng kí nhận những nhắc nhở có action là: com.pycitup.BroadcastReceiver.

Căn bản action này cũng chỉ là một String mà bạn mong muốn đặt là gì cũng được. Thông thường thì người ta sẽ đặt tên action giống với tên package áp dụng.

Có một sự khác biết lớn giữa 2 cách đăng kí là:Nếu đăng kí bằng cách dùng code thì khi activity bị stop thì việc lắng nghe broadcast cũng bị tạm dừng theo. Trong lúc đăng kí qua manifest thì sẽ lắng nghe trọn đời.

Cho nên, nếu bạn đăng kí receiver thông qua code thì nên hủy đăng kí khi activity bị stop. Kiểu như sau

protected fun onPause() {
  unregisterReceiver(mReceiver)
  super.onPause()
}

Vậy cách đăng kí receiver nào là tốt nhất?

Khuyến cáo của mình là tùy theo mục đích áp dụng của các bạn mà lựa chọn cách đăng kí cho thích hợp.

Nếu áp dụng mong muốn cập nhập ngay trên màn hình smartphone( như home screen, launcher, status bar, widget…) khi nhận nhắc nhở từ hệ thống hay từ áp dụng khác thì cách đăng kí qua manifest là phù hợp.

Xem Thêm  Syntax and basic data types - html css cơ bản

Trong lúc cũng nhận những nhắc nhở mà bạn chỉ mong muốn cập nhập khi người dùng đang ở áp dụng thì cách đăng kí bằng code là hợp lý hơn. Vì bạn sẽ chủ động đăng kí/ hủy đăng kí để tối ưu hiệu năng hệ thống.

Không những thế, có một số trường hợp ngoại lệ như action Intent.ACTION_TIME_TICK là bạn chẳng thể đăng kí trong manifest mà phải đăng kí bằng code. Android làm như thế là để tiết kiệm pin cho hệ thống.

4. Gửi Broadcast Sự kiện/Intent

Tất cả chúng ta đã giải quyết 2/3 giai đoạn trọng yếu của Broadcast Receiver trong Android. Phần cuối cùng chính là gửi nhắc nhở(Broadcast).

val intent = Intent()
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
intent.setAction("com.pycitup.BroadcastReceiver")
intent.putExtra("Foo", "Bar")
sendBroadcast(intent)

Tất cả chúng ta tạo một intent, sau đó cài đặt action cho intent này. Bước này là com.pycitup.BroadcastReceiver. Chính là action mà tất cả chúng ta đã sử dụng để đăng kí ở phần phía trên nội dung. Dữ liệu sẽ được mang vào intent thông qua hàm putExtra()

Cuối cùng gửi Broadcast bằng hàm sendBroadcast()

Mình giải thích thêm một tí nếu bạn nào để mắt trong đoạn code trên có một flag: FLAG_INCLUDE_STOPPED_PACKAGES. Căn bản thì flag này cho phép áp dụng vẫn nhận nhắc nhở trong trường hợp áp dụng được setup nhưng chưa chạy lần nào hoặc bị tắt bởi dụng cụ làm chủ hệ thống như task manager.

Các kiểu gửi Broadcasts

Nhìn chung, có 2 cách thức để gửi broadcasts:

  • Gửi Broadcasts theo cách thông thường: Tức là tất cả chúng ta sử dụng hàm Context.sendBradcast() như bạn vừa thấy ở trên. Đây là cách gửi broadcast không ăn nhập.& phía receiver cũng thế. Các receiver được đuổi theo một thứ tự không xác nhận, thường là cùng một lúc. Khuyết điểm của cách gửi đó là các reciever chẳng thể sử dụng kết quả của nhau
  • Gửi Broadcasts theo thứ tự:  Để làm được điều này, tất cả chúng ta sử dụng hàm Context.sendOrderedBroadcast() & nó chỉ định rõ receiver được nhận tại một thời điểm. Thứ tự Receiver nhận làm chủ bởi tính chất android:priority. Reciever có cùng mức độ ưu tiên sẽ được thực hiện theo thứ tự bỗng dưng. Khi mỗi reciever thực hiện, nó có thể chuyển kết quả đến receiver tiếp theo hoặc hủy bỏ toàn thể chuỗi broadcasts để không cho reciever khác thu được

Dưới đây là chẳng hạn cho cách gửi Broadcast theo thứ tự

// MySecondReceiver.kt
class MySecondReceiver:BroadcastReceiver() {
  private val TAG = MySecondReceiver::class.java!!.getSimpleName()
  fun onReceive(context:Context, intent:Intent) {
    val results = getResultExtras(true)
    results.putString("hierarchy", TAG)
    Log.{d}(TAG, "MySecondReceiver")
  }
}
// MyReceiver.kt
class MyReceiver:BroadcastReceiver() {
  private val TAG = MyReceiver::class.java!!.getSimpleName()
  fun onReceive(context:Context, intent:Intent) {
    val results = getResultExtras(true)
    val hierarchy = results.getString("hierarchy")
    results.putString("hierarchy", hierarchy + "->" + TAG)
    Log.{d}(TAG, "MyReceiver")
  }
}

Cuối cùng là khai báo đăng kí trong Manifest

<receiver
    android_name="com.pycitup.pyc.MyReceiver"
    >
    <intent-filter android_priority="1">
        <action android_name="com.pycitup.BroadcastReceiver" />
    </intent-filtervàgt;
</receivervàgt;
<receiver
    android_name="com.pycitup.pyc.MySecondReceiver"
    >
    <intent-filter android_priority="2">
        <action android_name="com.pycitup.BroadcastReceiver" />
    </intent-filtervàgt;
</receivervàgt;

Chú ý:
Các bạn để mắt đến mức độ ưu tiên của receiver thông qua thẻ android:priority. Mức ưu tiên càng cao thì sẽ được nhận đầu tiên. Mặc định, mức độ ưu tiên là 0

Xem Thêm  Cây lúa trong ngôn ngữ người Việt - ngon ngu lua

Kế tiếp là phần gửi Broadcast trong MainActivity.onCreate ():

val filter = IntentFilter("com.pycitup.BroadcastReceiver")
registerReceiver(object:BroadcastReceiver() {
  fun onReceive(context:Context, intent:Intent) {
    val results = getResultExtras(true)
    val hierarchy = results.getString("hierarchy")
    results.putString("hierarchy", hierarchy + "->" + TAG)
    Log.{d}(TAG, "Anonymous class broadcast receiver")
  }
}, filter)
val intent = Intent("com.pycitup.BroadcastReceiver")
sendOrderedBroadcast(intent, null, object:BroadcastReceiver() {
  fun onReceive(context:Context, intent:Intent) {
    val results = getResultExtras(true)
    val hierarchy = results.getString("hierarchy")
    println(hierarchy)
    Log.{d}(TAG, "Final Receiver")
  }
}, null, Activity.RESULT_OK, null, null)

& đây là kết quả khi bạn chạy áp dụng

﹕ MySecondReceiver
﹕ MyReceiver
﹕ Anonymous class broadcast receiver
﹕ MySecondReceiver->MyReceiver->MainActivity
﹕ Final Receiver

Như mình nói ở trên, bất cứ receiver nào cũng có thể hủy toàn thể chuỗi Broadcast để không cho các receiver khác thu được. Dễ dàng là gọi hàm abortBroadcast()

  • Dành riêng cho bạn: Tích hợp Google Drive vào áp dụng Android từ ?-Ż

5. Local BroadcastManager – Gửi Broadcast trong nội bộ áp dụng

Như các bạn đã biết thì khi gửi Broadcast thì bất cứ áp dụng nào đăng kí đều thu được. Thỉnh thoảng vì nguyên nhân bảo mật cho áp dụng mà tất cả chúng ta không mong muốn bất cứ áp dụng nào khác thu được. Những thông tin này chỉ được gửi bên trong áp dụng.

LocalBroadcast sẽ giúp bạn làm được điều đó.

LocalBroadcastManager.getInstance(this).registerReceiver(object:BroadcastReceiver() {
  fun onReceive(context:Context, intent:Intent) {
    val message = intent.getStringExtra("foo")
    Log.{d}("LocalBroadcastManager", "foo : " + message)
  }
}, IntentFilter("my-custom-event"))

Còn đây là cách gửi local broadcast

val intent = Intent("my-custom-event")
intent.putExtra("foo", "bar")
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)

& đừng quên hủy đăng kí trong hàm onPause()của Activity

protected fun onPause() {
  LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver)
  super.onPause()
}

6. Permissions

Có một số Broadcast cần phải yêu cầu permission. Tất nhiên là những permission này phải được sự đồng ý của người dùng.

Chẳng hạn:  Intent.ACTION_BOOT_COMPLETEDyêu cầu permission  RECEIVE_BOOT_COMPLETED

Các bạn khai báo permission trong Manifest như sau

<uses-permission android_name="android.permission.RECEIVE_BOOT_COMPLETED" />

Tất nhiên, đây chỉ là khai báo thôi, từ Android ʍ trở lên, bạn cần phải viết thêm code để yêu cầu người dùng đồng ý permission này cho áp dụng

Mặc dầu đa phần Broadcast không yêu cầu permission, không những thế cẩn tắc vô áy náy, bạn có thể kiểm soát tại đây

7. Kết luận

Như thế là tất cả chúng ta đã đi ngang qua toàn bộ các vấn đề của Broadcast Receiver trong Android. Mặc dầu BroadcastReceiver không phải là vấn đề khó nhưng cũng có nhiều điểm thú vị phải không?

Nội dung sau tất cả chúng ta sẽ cùng với nhau khám phá về giải quyết đa luồng thông qua thread, Asynctask trong Android

Các bạn đừng quên để lại phản hồi nếu có bất cứ khúc mắc nào nhé

Viết một bình luận