BroadcastReceiver應用詳解


問渠那得清如許?為有源頭活水來。南宋.朱熹《觀書有感》

據說程序員是最愛學習的群體,IT男都知道,這個行業日新月異,必須不斷地學習新知識,不斷地為自己入新鮮的血液,才能使自己跟上技術的步伐。

今天我們來講一下Android中BroadcastReceiver的相關知識。

BroadcastReceiver也就是“廣播接收者”的意思,顧名思義,它就是用來接收來自系統和應用中的廣播。

在Android系統中,廣播體現在方方面面,例如當開機完成后系統會產生一條廣播,接收到這條廣播就能實現開機啟動服務的功能;當網絡狀態改變時系統會產生一條廣播,接收到這條廣播就能及時地做出提示和保存數據等操作;當電池電量改變時,系統會產生一條廣播,接收到這條廣播就能在電量低時告知用戶及時保存進度,等等。

Android中的廣播機制設計的非常出色,很多事情原本需要開發者親自操作的,現在只需等待廣播告知自己就可以了,大大減少了開發的工作量和開發周期。而作為應用開發者,就需要數練掌握Android系統提供的一個開發利器,那就是BroadcastReceiver。下面我們就對BroadcastReceiver逐一地分析和演練,了解和掌握它的各種功能和用法。

首先,我們來演示一下創建一個BroadcastReceiver,並讓這個BroadcastReceiver能夠根據我們的需要來運行。

要創建自己的BroadcastReceiver對象,我們需要繼承android.content.BroadcastReceiver,並實現其onReceive方法。下面我們就創建一個名為MyReceiver廣播接收者:

package com.scott.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class MyReceiver extends BroadcastReceiver {
    
    private static final String TAG = "MyReceiver";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        String msg = intent.getStringExtra("msg");
        Log.i(TAG, msg);
    }

}

 

在onReceive方法內,我們可以獲隨廣播而來的Intent中的數據,這非常重要,就像無線電一樣,包含很多有用的信息。

在創建完我們的BroadcastReceiver之后,還不能夠使它進入工作狀態,我們需要為它冊一個指定的廣播地址。沒有冊廣播地址的BroadcastReceiver就像一個缺少選台按鈕的收音機,雖然功能俱備,但也無法收到電台的信號。下面我們就來介紹一下如何為BroadcastReceiver冊廣播地址。

靜態

靜態冊是在AndroidManifest.xml文件中配置的,我們就來為MyReceiver冊一個廣播地址:

<receiver android:name=".MyReceiver">
            <intent-filter>
                <action android:name="android.intent.action.MY_BROADCAST"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

配置了以上信息之后,只要是android.intent.action.MY_BROADCAST這個地址的廣播,MyReceiver都能夠接收的到。意,這種方式的冊是常駐型的,也就是說當應用關閉后,如果有廣播信息傳來,MyReceiver也會被系統調用而自動運行。

然后再次運行程序,控制台打印如下:

 

此次,只有第一個接收者執行了,其它兩個都沒能執行,因為廣播被第一個接收者終止了。

原文地址:

http://blog.csdn.net/liuhe688/article/details/6955668

原文中還有一些實例,可以參考。

動態

動態冊需要在代碼中動態的指定廣播地址並冊,通常我們是在Activity或Service冊一個廣播,下面我們就來看一下冊的代碼:

MyReceiver receiver = new MyReceiver();
        
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.MY_BROADCAST");
        
registerReceiver(receiver, filter);

意,registerReceiver是android.content.ContextWrapper類中的方法,Activity和Service都繼承了ContextWrapper,所以可以直接調用。在實際應用中,我們在Activity或Service中冊了一個BroadcastReceiver,當這個Activity或Service被銷毀時如果沒有解除冊,系統會報一個異常,提示我們是否忘記解除冊了。所以,記得在特定的地方執行解除冊操作:

@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(receiver);
}

執行這樣行代碼就可以解決問題了。意,這種冊方式與靜態冊相反,不是常駐型的,也就是說廣播會跟隨程序的生命周期。

我們可以根據以上任意一種方法完成冊,當冊完成之后,這個接收者就可以正常工作了。我們可以用以下方式向其發送一條廣播:

    public void send(View view) {
        Intent intent = new Intent("android.intent.action.MY_BROADCAST");
        intent.putExtra("msg", "hello receiver.");
        sendBroadcast(intent);
    }

意,sendBroadcast也是android.content.ContextWrapper類中的方法,它可以將一個指定地址和參數信息的Intent對象以廣播的形式發送出去。

點擊發送按鈕,執行send方法,控制台打印如下:

看到這樣的打印信息,表明我們的廣播已經發出去了,並且被MyReceiver准確無誤的接收到了。

上面的例子只是一個接收者來接收廣播,如果有多個接收者都冊了相同的廣播地址,又會是什么情況呢,能同時接收到同一條廣播嗎,相互之間會不會有干擾呢?這就涉及到普通廣播和有序廣播的概念了。

普通廣播(Normal Broadcast)

普通廣播對於多個接收者來說是完全異步的,通常每個接收者都無需等待即可以接收到廣播,接收者相互之間不會有影響。對於這種廣播,接收者無法終止廣播,即無法阻止其他接收者的接收動作。

為了驗證以上論斷,我們新建三個BroadcastReceiver,演示一下這個過程,FirstReceiver、SecondReceiver和ThirdReceiver的代碼如下:

package com.scott.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class FirstReceiver extends BroadcastReceiver {
    
    private static final String TAG = "NormalBroadcast";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        String msg = intent.getStringExtra("msg");
        Log.i(TAG, "FirstReceiver: " + msg);
    }

}
public class SecondReceiver extends BroadcastReceiver {
    
    private static final String TAG = "NormalBroadcast";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        String msg = intent.getStringExtra("msg");
        Log.i(TAG, "SecondReceiver: " + msg);
    }

}
public class ThirdReceiver extends BroadcastReceiver {
    
    private static final String TAG = "NormalBroadcast";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        String msg = intent.getStringExtra("msg");
        Log.i(TAG, "ThirdReceiver: " + msg);
    }

}

然后再次點擊發送按鈕,發送一條廣播,控制台打印如下:

 

看來這三個接收者都接收到這條廣播了,我們稍微修改一下三個接收者,在onReceive方法的最后一行添加以下代碼,試圖終止廣播:

abortBroadcast();

再次點擊發送按鈕,我們會發現,控制台中三個接收者仍然都打印了自己的日志,表明接收者並不能終止廣播。

 

有序廣播(Ordered Broadcast)

有序廣播比較特殊,它每次只發送到優先級較高的接收者那里,然后由優先級高的接受者再傳播到優先級低的接收者那里,優先級高的接收者有能力終止這個廣播。

為了演示有序廣播的流程,我們修改一下上面三個接收者的代碼,如下:

package com.scott.receiver;

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

public class FirstReceiver extends BroadcastReceiver {
    
    private static final String TAG = "OrderedBroadcast";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        String msg = intent.getStringExtra("msg");
        Log.i(TAG, "FirstReceiver: " + msg);
        
        Bundle bundle = new Bundle();
        bundle.putString("msg", msg + "@FirstReceiver");
        setResultExtras(bundle);
    }

}
public class SecondReceiver extends BroadcastReceiver {
    
    private static final String TAG = "OrderedBroadcast";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        String msg = getResultExtras(true).getString("msg");
        Log.i(TAG, "SecondReceiver: " + msg);
        
        Bundle bundle = new Bundle();
        bundle.putString("msg", msg + "@SecondReceiver");
        setResultExtras(bundle);
    }

}
public class ThirdReceiver extends BroadcastReceiver {
    
    private static final String TAG = "OrderedBroadcast";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        String msg = getResultExtras(true).getString("msg");
        Log.i(TAG, "ThirdReceiver: " + msg);
    }

}

我們意到,在FirstReceiver和SecondReceiver中最后都使用了setResultExtras方法將一個Bundle對象設置為結果集對象,傳遞到下一個接收者那里,這樣以來,優先級低的接收者可以用getResultExtras獲到最新的經過處理的信息集合。

 

代碼改完之后,我們需要為三個接收者冊廣播地址,我們修改一下AndroidMainfest.xml文件:

        <receiver android:name=".FirstReceiver">
            <intent-filter android:priority="1000">
                <action android:name="android.intent.action.MY_BROADCAST"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>
        <receiver android:name=".SecondReceiver">
            <intent-filter android:priority="999">
                <action android:name="android.intent.action.MY_BROADCAST"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>
        <receiver android:name=".ThirdReceiver">
            <intent-filter android:priority="998">
                <action android:name="android.intent.action.MY_BROADCAST"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

我們看到,現在這三個接收者的<intent-filter>多了一個android:priority屬性,並且依次減小。這個屬性的范圍在-1000到1000,數值越大,優先級越高。

 

現在,我們需要修改一下發送廣播的代碼,如下:

    public void send(View view) {
        Intent intent = new Intent("android.intent.action.MY_BROADCAST");
        intent.putExtra("msg", "hello receiver.");
        sendOrderedBroadcast(intent, "scott.permission.MY_BROADCAST_PERMISSION");
    }

意,使用sendOrderedBroadcast方法發送有序廣播時,需要一個權限參數,如果為null則表示不要求接收者聲明指定的權限,如果不為null,則表示接收者若要接收此廣播,需聲明指定權限。這樣做是從安全角度考慮的,例如系統的短信就是有序廣播的形式,一個應用可能是具有攔截垃圾短信的功能,當短信到來時它可以先接受到短信廣播,必要時終止廣播傳遞,這樣的軟件就必須聲明接收短信的權限。

 

所以我們在AndroidMainfest.xml中定義一個權限:

    <permission android:protectionLevel="normal"
                android:name="scott.permission.MY_BROADCAST_PERMISSION" />

然后聲明使用了此權限:

<uses-permission android:name="scott.permission.MY_BROADCAST_PERMISSION" />

關於這部分如果有不明白的地方可以參考我之前寫過的一篇文章:Android聲明和使用權限

然后我們點擊發送按鈕發送一條廣播,控制台打印如下:

我們看到接收是按照順序的,第一個和第二個都在結果集中加入了自己的標記,並且向優先級低的接收者傳遞下去。

既然是順序傳遞,試着終止這種傳遞,看一看效果如何,我們修改FirstReceiver的代碼,在onReceive的最后一行添加以下代碼:

abortBroadcast();

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM