Tìm hiểu về BroadcastReceiver

1. Động cơ

Thiên thời

Một ngày chủ nhật đẹp trời sau cơn mưa tầm tã đêm qua, đội tuyển bóng đá Framgia cũng dành chiến thắng 3-0 hoành tráng (hoho)

Địa lợi

Dự án hiện tại đang tham gia sử dụng BroadcastReceiver khá nhiều

Nhân hòa

Một newbie đích thực với Android có tham vọng hiểu biết được thêm ít nhiều cho dễ lấy vợ

2. Về BroadcastReceiver (người nhận truyền tin)

Android BroadcastReceiver là một thành phần nơi bạn có thể đăng ký sự kiện của hệ thống (system) hay ứng dụng (application). Bạn sẽ nhận được thông báo về các sự kiện một khi đã đăng ký. Việc phát tin (Broadcast) bắt nguồn từ hệ thống cũng như từ các ứng dụng (applications). Ví dụ về việc phát tin bắt nguồn từ hệ thống có thể kể ra như thông báo pin yếu. Với cấp độ ứng dụng có thể kể ra như khi bạn download một file nhạc. Ứng dụng nhạc này sẽ nhận được thông báo về việc download, sau khi kết thúc sẽ đưa bài hát này vào danh sách để bật. Để thực hiện được việc này, ứng dụng nhạc cần thiết phải đăng ký cho sự kiện. Một ví dụ đơn giản khác, người dùng sẽ nhận thông báo khi pin của máy mình đã xuống dưới một mức độ nào đấy

Trong ví dụ sau các bạn sẽ biết cách để tạo ra một broadcast receiver tùy biến trong android

Điều này có nghĩa sự kiện ACTION_BATTERY_LOW đã được đăng ký và hệ thống Android sẽ phát khi lượng pin còn lại đã xuống thấp. Những thông báo có tin nhắn mới hay về wifi đều là các broadcast receivers

Có 2 cách để đăng ký Android broadcast receiver

  • Một là phương thức tĩnh khi đăng ký broadcast receiver trong ứng dụng thông qua file AndroidManifest.xml.
  • Hai là phương thức động để đăng ký broadcast receiver thông qua việc sử dụng method Context.registerReceiver(). Các broadcast receiver được đăng ký động có thể được gỡ bởi method Context.unregisterReceiver().

Chúng ta phải hết sức cẩn thận khi tạo ra các broadcast receiver động. Nếu quên việc gỡ đăng ký broadcast receiver, hệ thống sẽ thông báo lỗi lộ (leaked) broadcast receiver

Tạo broadcast receiver và sử dụng method onReceive()

Một broadcast receiver sẽ mở rộng (extends) class trừu tượng (abstract) BroadcastReceiver. Điều này có ý nghĩa bạn phải sử dụng method onReceive() của class chính (base) này. Mỗi khi có sự kiện xảy ra, Android sẽ gọi method onReceive() ở broadcast receiver đã được đăng ký. Ví dụ, nếu bạn đăng ký cho sự kiện ACTION_POWER_CONNECTED, mỗi khi di động được kết nối với nguồn điện, method onReceive() broadcast receiver của bạn sẽ được gọi

Method onReceive()

Method onReceive() có 2 đối số (argument)

onReceive(Context context, Intent intent)

context (phạm vi) có thể được sử dụng để chạy service hoặc activity và intent là object (đối tượng) cùng với action (hành động) bạn đã sử dụng để đăng ký receiver của bạn. Nó có thể chứa các thông tin thêm mà bạn có thể dùng để implementation (thi hành).

Đăng ký Broadcast Receiver của bạn

Đăng ký Broadcast Receiver tĩnh

Giống như đã nói ở trên, broadcast receiver có thể đăng ký tĩnh thông qua file AndroidManifest.xml. Element (yếu tố) được sử dụng để định rõ sự kiện (event) mà receiver nên phản ứng lại. Chính vì thế mỗi lần sự kiện này (MyBroadcast) xảy ra, method onReceive() của MyBroadcastReceiver sẽ được gọi.

Khi method onReceive() kết thúc, BroadcastReceiver của bạn sẽ bị hủy.

Một vài sự kiện cần có PERMISSIONS (cho phép)

Ví dụ

  • <action android:name="android.intent.action.PHONE_STATE" />

Chúng ta cần cho thêm:

  • <uses-permission android:name="android.permission.READ_PHONE_STATE" />

File AndroidManifest.xml cuối cùng sẽ như sau:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcastreceiverdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.broadcastreceiverdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
       <receiver android:name="BroadCastReceiver_Name" >
            <intent-filter>
                <action android:name="Event_Name" >
                    </action>
            </intent-filter>
        </receiver>
    </application>
</manifest>

Đăng ký broadcast receiver động

BroadcastReceiver mReceiver = new MyBroadcastReceiver();
registerReceiver(this.myReceiver, new IntentFilter("MyBroadcast"));

Ở đây this chính là context hiện nay của bạn.

Tránh những task chạy lâu

Chúng ta cần tránh những task chạy lâu trong các Broadcast receiver. Đối với các task lâu chúng ta có thể chạy service trong receiver. Các receiver được đăng ký động sẽ được gọi trong UI thread. Các receiver được đăng ký động sẽ hạn chế bất cứ thao tác UI (giao diện người dùng), vì vậy method onReceive() sẽ được chạy ở tốc độ cao nhất. Application có thể trở nên chậm chạp và phát sinh lỗi tồi tệ “Application Not Responding”.

Application ví dụ

Tôi đã đăng ký tĩnh MyBroadcastReceiver trong file AndroidManifest.xml. Ở ví dụ này tôi sẽ sử dụng event riêng đó là MyBroadcast.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcastreceiverdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.broadcastreceiverdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name="MyBroadcastReceiver" >
            <intent-filter>
            	<action android:name="MyBroadcast" >
                </action>
            </intent-filter>
        </receiver>
    </application>
</manifest>

Tôi gửi broadcast (truyền tin) MyBroadcast từ activity chính như sau:

Intent intent = new Intent();
intent.setAction("MyBroadcast");
intent.putExtra("value", 1000);
sendBroadcast(intent);

Tôi gửi broadcast cùng một thông tin thêm là value=1000. Thông tin thêm này có thể nhận được bởi broadcast receiver theo cách như sau:

Bundle extras = intent.getExtras();
if (extras != null) {
   if(extras.containsKey("value")){
      String value=extras.get("value");
   }
}

MainActivity.java hoàn thiện sẽ như sau:

package com.example.broadcastreceiverdemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

public class MainActivity extends Activity {
   @Override
   protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     Intent intent = new Intent();
     intent.setAction("MyBroadcast");
     intent.putExtra("value", 1000);
     sendBroadcast(intent);
   }
}

Broadcast receiver hoàn thiện sẽ như sau:

package com.example.broadcastreceiverdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

public class MyBroadcastReceiver extends BroadcastReceiver{
 @Override
 public void onReceive(Context context, Intent intent) {
     Bundle extras = intent.getExtras();
     if (extras != null) {
        if(extras.containsKey("value")){
           System.out.println("Value is:" + extras.get("value"));
        }
     }
  }
}

Kết quả sẽ được in ra console.

Các Intent trong Broadcast receiver

Các Intent được sử dụng trong broadcast receiver khác với Intent sử dụng để chạy activity. Intent dùng để broadcasting sẽ chạy ở background (phía sau) và người dùng sẽ không nhận thấy intent này. Tuy nhiên intent được sử dụng để chạy activity người dùng có thể nhìn thấy

Security issues with Android Broadcast receivers

Từ Android 3.1, hệ thống android sẽ không nhận được intent ngoài (external). Nếu bạn sử dụng các phiên bản trước, hãy cân nhắc các điều sau

  • Hãy cho broadcast receiver không dùng được với các application ngoài (external) sử dụng android:export=”false. Nếu không thì các application khác có thể lạm dụng chúng.
  • Hãy chắc chắn rằng các broadcast mà bạn gửi không nhận được từ các application khác. Hãy chỉ định hạn chế (limitation) để broadcast chỉ có thể nhận trong application của bạn.
  • Cũng giống như thế khi đăng ký một receiver, hãy chắc chắn rằng bạn không nhận các broadcast của các applications khác.

All Rights Reserved