Computer >> Hướng Dẫn Máy Tính >  >> Hệ Thống >> Android

Làm chủ Broadcast Receiver: Hướng dẫn cho Beginner phát hiện thay đổi Network

Giả sử bạn có ứng dụng phụ thuộc vào kết nối internet ổn định. Bạn muốn app được thông báo khi kết nối internet thay đổi. Làm sao? Giải pháp có thể là service luôn kiểm tra kết nối. Triển khai này xấu vì nhiều lý do nên không xem xét. Giải pháp là Broadcast Receiver, nó sẽ lắng nghe thay đổi bạn nói. Broadcast receiver luôn nhận được broadcast, bất kể trạng thái app. Không quan trọng app đang chạy, background hay không chạy.

Bối cảnh

Broadcast receiver là component trong ứng dụng Android lắng nghe broadcast message (hoặc event) từ các nguồn:

  • Từ ứng dụng khác
  • Từ hệ thống
  • Từ ứng dụng của bạn

Nghĩa là, chúng được invoke khi hành động nhất định xảy ra mà chúng được lập trình để lắng nghe (Ví dụ: một broadcast).

Broadcast đơn giản là message gói trong Intent object. Broadcast có thể implicit hoặc explicit.

  • Một implicit broadcast là broadcast không target app cụ thể nên không exclusive cho app. Để đăng ký, cần dùng IntentFilter và khai báo trong manifest. Cần làm tất cả vì Android OS duyệt qua tất cả intent filter khai báo trong manifest xem có match. Do hành vi này, implicit broadcast không có target attribute. Ví dụ implicit broadcast: action tin nhắn SMS đến.
  • Một explicit broadcast là broadcast target cụ thể cho app trên component biết trước. Xảy ra do target attribute chứa package name hoặc component class name.

Có hai cách khai báo receiver:

  1. Khai báo trong AndroidManifest.xml với tag <receiver> (còn gọi static)
<receiver android:name=".YourBrodcastReceiverClass" android:exported="true"> <intent-filter> <!-- Actions bạn muốn lắng nghe, ví dụ dưới --> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver>
AndroidManifest.xml

Bạn nhận thấy receiver khai báo có property exported=”true”. Attribute này cho receiver biết nó nhận broadcast từ ngoài phạm vi app.

2. Hoặc dynamic bằng cách đăng ký instance với registerReceiver (context registered)

public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter);

Triển khai

Để tạo broadcast receiver riêng, phải extend BroadcastReceiver parent class và override method bắt buộc onReceive:

public void onReceive(Context context, Intent intent) { //Triển khai logic tại đây }

Gộp tất cả lại:

public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { StringBuilder sb = new StringBuilder(); sb.append("Action: " + intent.getAction() + "\n"); sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n"); String log = sb.toString(); Toast.makeText(context, log, Toast.LENGTH_LONG).show(); } }
MyBroadcastReceiver.java
⚠️Method onReceive chạy trên main thread, nên thực thi phải ngắn.

Nếu process dài, hệ thống có thể kill process sau khi method return. Để tránh, dùng goAsync hoặc schedule job. Đọc thêm về schedule job ở cuối bài.

Ví dụ Đăng ký động (Dynamic Registration)

Để đăng ký receiver với context, đầu tiên instantiate instance broadcast receiver:

BroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();

Sau đó đăng ký tùy context cụ thể:

IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); this.registerReceiver(myBroadcastReceiver, filter);
Tham số đầu tiên IntentFilter là string đại diện action

Đừng quên unregister broadcast receiver khi không cần nữa

@Override protected void onStop() { super.onStop(); unregisterReceiver(myBroadcastReceiver); }

Phát sự kiện Broadcast (Broadcasting An Event)

Có ba cách gửi broadcast:

  1. Method sendOrderedBroadcast gửi broadcast đến một receiver tại một thời điểm. Mỗi broadcast có thể truyền data cho receiver tiếp theo, hoặc dừng propagation.
  2. Method sendBroadcast tương tự, khác: tất cả receiver nhận message và không phụ thuộc nhau.
  3. Method LocalBroadcastManager.sendBroadcast chỉ gửi broadcast đến receiver định nghĩa trong app, không vượt phạm vi app. Ví dụ gửi custom broadcast

https://giphy.com/gifs/23gUJhHyWkXEwl7UYV/html5

Làm chủ Broadcast Receiver: Hướng dẫn cho Beginner phát hiện thay đổi Network
Ảnh bởi John Gibbons trên Unsplash

Gotchas Và Điều Cần Chú Ý

  • Đừng gửi sensitive data qua implicit broadcast, vì bất kỳ app nào lắng nghe sẽ nhận được. Ngăn chặn bằng cách chỉ định package hoặc gắn permission cho broadcast
  • Đừng start activity từ broadcast nhận được vì UX kém. Nên hiển thị notification.

Các bullet dưới đây đề cập thay đổi broadcast receiver liên quan mỗi Android OS version (từ 7.0). Mỗi version, giới hạn nhất định áp dụng và hành vi thay đổi. Nhớ các giới hạn khi dùng broadcast receiver.

  • 7.0 trở lên (API level 24) - Hai system broadcast bị disable: Action_New_Picture và Action_New_Video (nhưng đưa lại trong Android O cho registered receiver)
  • 8.0 trở lên (API level 26) - Đa số implicit broadcast cần đăng ký dynamic, không static (trong manifest). Tìm broadcast whitelisted tại link này.
  • 9.0 trở lên (API level 28) - Thông tin ít hơn trên Wi-Fi system broadcast và Network_State_Changed_Action.

Thay đổi Android O là cần lưu ý nhất. Lý do thay đổi: gây performance issue, hao pin, hại UX. Xảy ra vì nhiều app (kể cả không chạy) lắng nghe system-wide change, khi change xảy ra, hỗn loạn. Hãy tưởng tượng mọi app đăng ký action, chạy lên kiểm tra có cần làm gì. Cân nhắc Wi-Fi state thay đổi thường xuyên, bạn hiểu tại sao thay đổi.

Lựa chọn thay thế Broadcast Receiver

Để dễ điều hướng qua các hạn chế, dưới đây là breakdown component khác dùng khi thiếu broadcast receiver. Mỗi cái có trách nhiệm và use case khác, hãy map cái nào phù hợp nhu cầu.

  • LocalBroadcastManager - Như đề cập, chỉ hợp lệ cho broadcast trong app
  • Scheduling A Job - Job chạy tùy signal hoặc trigger nhận, bạn có thể thấy broadcast bạn lắng nghe có thể thay bằng job. JobScheduler đảm bảo job finish, nhưng cân nhắc system factor (time, conditions) để quyết định khi chạy. Tạo job, override method onStartJob. Method chạy main thread, đảm bảo finish trong thời gian hạn chế. Cần logic phức tạp, hãy start background task. Return boolean: true nghĩa action vẫn đang perform, false job done

Nếu muốn trải nghiệm trực tiếp niềm vui và kỳ diệu của broadcast receiver, follow link repo tôi setup:

  1. Custom Broadcast (với manifest declaration)
  2. Registering Broadcast (không khai báo manifest)
  3. LocalBroadcastManager

Broadcast over.