Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android四大組件之BroadcastReceiver

Android四大組件之BroadcastReceiver

編輯:關於android開發

Android四大組件之BroadcastReceiver


BroadcastReceiver 簡介

BroadcastReceiver 廣播是一種訂閱–通知 事件,廣播接收者向Android系統 register (訂閱廣播),廣播發送者向Adnroid系統 sendBroadCast(發送廣播),然後Android 系統通知所有注冊該廣播的接收者,廣播接收者收到自己注冊的廣播之後實現自己想做的事情(該事情一般不超過10s,否則應用會出現ANR)。

BroadCast的分類:

無序廣播:也就是普通廣播,只要注冊了該action的廣播接收者都能收到該廣播,且沒有先後順序。

有序廣播:廣播接收者按照優先級高低依次接受該廣播,並且優先接收的廣播可以通過setResultExtras(Bundle)方法,將處理好的結果傳送到下一個廣播接收者那裡。

粘性廣播:發送廣播調用的方法 sendStickyBroadcast(Intent),和sendBroadcast(Intent)不同。
粘性廣播會一直保留在內存當中,直到有廣播接收者注冊該廣播,該廣播才算結束。不好解釋,等會具體看例子。

BroadCase的使用:

一.普通廣播:

根據注冊方式不同可以分為 靜態注冊廣播和動態注冊廣播。

1.靜態注冊廣播使用實例

AndroidManifest.xml 如下:




    
        
            
                

                
            
        

        
        
            
                
            
        
    

2.廣播接收者實現如下:

package com.xjp.mybroadcast;

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

/**
 * Description:靜態廣播接收器
 * User: xjp
 * Date: 2015/5/14
 * Time: 14:56
 */

public class BroadCastReceive1 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //TODO 接收到廣播之後處理自己的事情
        String action = intent.getAction();
        String result = intent.getStringExtra("key");
        MyLog.d("the BroadCast action is " + action + "   the BroadCast receive result is " + result);
    }
}

3.廣播發送者實現如下:

package com.xjp.mybroadcast;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;


public class MainActivity extends ActionBarActivity implements View.OnClickListener {

    private Button btnSend;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnSend = (Button) findViewById(R.id.button);
        btnSend.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                sendBraodCast();
                break;
        }
    }

    private void sendBraodCast() {

        /**
         * 申明靜態廣播的 action 行為
         */
        String action = "com.xjp.mybroadcast.BroadCastReceive1";
        Intent intent = new Intent(action);
        intent.putExtra("key", "靜態廣播測試");
        sendBroadcast(intent);
    }
}

打印結果如下:
\

4.靜態注冊廣播特點:

注冊廣播在 AndroidManifest.xml中。 廣播接收者需重新 繼承 BroadcastReceiver 類來實現 onReceive()抽象方法。 應用退出無需 注銷廣播,因此導致:即使廣播退出之後,如果有其他應用發送該action行為的廣播,此應用還是能接收到該廣播的,也就是還會打印上面的 結果。

二.動態廣播:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;


public class MainActivity extends ActionBarActivity implements View.OnClickListener {

    private Button btnSend;

    private BroadCastReceive2 myReceive;

    private IntentFilter filter;

    private final static String ACTION = "com.xjp.mybroadcast.BroadCastReceive2";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnSend = (Button) findViewById(R.id.button);
        btnSend.setOnClickListener(this);

        myReceive = new BroadCastReceive2();
        filter = new IntentFilter();
        filter.addAction(ACTION);

    }


    @Override
    protected void onResume() {
        /**
         * 注冊廣播
         */

        LocalBroadcastManager.getInstance(this).registerReceiver(myReceive, filter);//官方建議使用

//        this.registerReceiver(myReceive, filter);

        super.onResume();
    }


    @Override
    protected void onPause() {
        /**
         * 注銷廣播
         */

        LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceive);//官方建議使用

//        this.unregisterReceiver(myReceive);

        super.onPause();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                sendBraodCast();
                break;
        }
    }

    private void sendBraodCast() {

        /**
         * 申明廣播的 action 行為
         */
        Intent intent = new Intent(ACTION);
        intent.putExtra("key", "動態廣播測試");

        /**
         * 官方提倡使用如下發送廣播,原因是更快,更安全,不會導致內存洩漏
         */
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

//        this.sendBroadcast(intent);
    }


    /**
     * 內部類實現廣播接收器
     */
    private class BroadCastReceive2 extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //TODO 接收到廣播之後處理自己的事情
            String action = intent.getAction();
            String result = intent.getStringExtra("key");
            MyLog.d("the BroadCast action is " + action + "   the BroadCast receive result is " + result);
        }
    }
}

動態廣播特點

在代碼中調用registerReceiver()方法 注冊廣播。 廣播接收者需重新 繼承 BroadcastReceiver 類實現內部類。 動態廣播在應用退出時需要 調用unregisterReceiver()方法來注銷廣播。如果應用退出時沒有注銷廣播,會報如下錯誤:這裡寫圖片描述
因此,我們通常的做法是:在 onResume()中注冊廣播,在onPause中注銷廣播。 當廣播注銷之後就接收不到任何系統發送的廣播了。

三.有序廣播:

示例:


package com.xjp.mybroadcast; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.View; import android.widget.Button; public class MainActivity extends ActionBarActivity implements View.OnClickListener { private Button btnSend; private BroadCastReceive2 myReceive; private BroadCastReceive3 myReceive3; private IntentFilter filter; private IntentFilter filter3; private final static String ACTION = "com.xjp.mybroadcast.BroadCastReceive2"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnSend = (Button) findViewById(R.id.button); btnSend.setOnClickListener(this); myReceive = new BroadCastReceive2(); filter = new IntentFilter(); filter.addAction(ACTION); filter.setPriority(2);//設置廣播的優先級, -1000~1000 ,數字越大,優先級越高。 myReceive3 = new BroadCastReceive3(); filter3 = new IntentFilter(); filter3.addAction(ACTION); filter3.setPriority(1); } @Override protected void onResume() { /** * 注冊廣播 */ registerReceiver(myReceive, filter); registerReceiver(myReceive3, filter3); super.onResume(); } @Override protected void onPause() { /** * 注銷廣播 */ unregisterReceiver(myReceive); unregisterReceiver(myReceive3); super.onPause(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: sendBraodCast(); break; } } private void sendBraodCast() { /** * 申明廣播的 action 行為 */ Intent intent = new Intent(ACTION); intent.putExtra("key", "有序廣播測試"); this.sendOrderedBroadcast(intent, null); } /** * 內部類實現廣播接收器 */ private class BroadCastReceive2 extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //TODO 接收到廣播之後處理自己的事情 String action = intent.getAction(); String result = intent.getStringExtra("key"); MyLog.d("the BroadCast action is " + action + " the BroadCast receive result is " + result); Bundle bundle = new Bundle(); bundle.putString("key", "有序廣播處理之後" + "\n" + "再次發送給下一個廣播接收者"); intent.putExtra("bundle", bundle); setResultExtras(bundle); //切斷廣播,不再讓此廣播繼續往下發送。 // abortBroadcast(); } } /** * 內部類實現廣播接收器 */ private class BroadCastReceive3 extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //TODO 接收到廣播之後處理自己的事情 String action = intent.getAction(); //要不要接受上一個廣播接收器receiver2傳來的的數據 Bundle bundle = getResultExtras(true); MyLog.d("the BroadCast action is " + action + " the BroadCast receive result is " + bundle.getString("key")); } } } 

有序廣播特點

所有廣播接收者的action是一致的,發送有序廣播調用 sendOrderedBroadcast()方法。 有序廣播的接收者需要調用setPriority()方法設置廣播接收者的優先級。數字越大,優先接受廣播。 有序廣播如果需要終止 廣播繼續往下發送,可以調用 abortBroadcast()方法切斷廣播。 先接收廣播者可以將自己的處理結果通過setResultExtras()方法繼續傳遞給下一個廣播接收者。 後接收者可以調用 getResultExtras(true)來自己決定是否接收上一個廣播傳遞過來的數據。

四.粘性廣播:

示例 需要在 AndroidManifest.xml中添加 權限:

  

發送廣播的Activity

package com.xjp.mybroadcast;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;


/**
 * 發送廣播的Activity
 */
public class MainActivity extends ActionBarActivity implements View.OnClickListener {

    private Button btnSend;


    private final static String ACTION = "com.xjp.mybroadcast.BroadCastReceive1";
    private final static String ACTION1 = "com.xjp.mybroadcast.BroadCastReceive2";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnSend = (Button) findViewById(R.id.button);
        btnSend.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                sendBraodCast();
                break;
        }
    }

    private void sendBraodCast() {

        /**
         * 申明廣播的 action 行為
         */
        Intent intent = new Intent(ACTION);
        intent.putExtra("key", "普通廣播測試");
        sendBroadcast(intent);

        Intent intent1 = new Intent(ACTION1);
        intent1.putExtra("key", "粘性廣播測試");
        sendStickyBroadcast(intent1);
        startActivity(new Intent(this, RecevieActivity.class));
    }
}

接受廣播的Activity

package com.xjp.mybroadcast;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;

/**
 * Description:接受廣播的Activity
 * User: xjp
 * Date: 2015/5/14
 * Time: 17:03
 */

public class RecevieActivity extends Activity {

    private final static String ACTION1 = "com.xjp.mybroadcast.BroadCastReceive1";
    private final static String ACTION2 = "com.xjp.mybroadcast.BroadCastReceive2";

    private Receive receive;

    private IntentFilter filter1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        receive = new Receive();

        filter1 = new IntentFilter();
        filter1.addAction(ACTION1);
        filter1.addAction(ACTION2);

    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(receive, filter1);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(receive);
    }

    private class Receive extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            String result = intent.getStringExtra("key");
            MyLog.d("the BroadCast action is " + action + "   the BroadCast receive result is " + result);
        }
    }
}

打印結果如下:
這裡寫圖片描述
從結果來看,只有粘性廣播才能接收到廣播信息。

粘性廣播特點:

需要在AndroidManifest.xml中添加權限

粘性廣播發送除了調用方法不同sendStickyBroadcast(intent1),其他都一樣。

一般廣播都是先注冊廣播,才能接收到廣播,而粘性廣播可以做到先發送廣播,哪裡需要接收該廣播就哪裡注冊,可以後注冊廣播拿到廣播的結果。這就是 普通廣播和粘性廣播的區別。從示例中也看出了普通廣播在跳轉到ReceiveActivity中是接受不到廣播發送者發出的廣播的,只有粘性廣播才能接收到。

有人會奇怪,平時也沒看到哪裡使用粘性廣播??其實我也是看到Android 系統中 監測電池電量部分發現的。貼上代碼如下:

// Register for the battery changed event
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);

/ Intent is sticky so using null as receiver works fine
// return value contains the status
Intent batteryStatus = this.registerReceiver(null, filter);

// Are we charging / charged?
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING
  || status == BatteryManager.BATTERY_STATUS_FULL;

boolean isFull = status == BatteryManager.BATTERY_STATUS_FULL;

// How are we charging?
int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC; 

廣播的生命周期:

當廣播接收者接收到廣播調用完onReceive()方法之後,廣播的生命周期就結束了。
因此廣播接收器不能執行超過10s耗時任務,也不能在onReceive()方法中創建Thread 來執行耗時任務,你可以開啟一個Service來執行後台耗時任務,具體可以參考Android 四大組件之Service 的生命周期和使用。

廣播的大概原理:

我們知道,只有先注冊了某個廣播之後,廣播接收者才能收到該廣播。廣播注冊的一個行為是將自己感興趣的IntentFilter注冊到Android系統的AMS(ActivityManagerService)中,裡面保存了一個IntentFilter列表。廣播發送者將自己的IntentFilter 的action行為發送到AMS中,然後遍歷AMS中的IntentFilter列表,看誰訂閱了該廣播,然後將消息遍歷發送到注冊了相應IntentFilter的Activity或者Service中—–也就是會調用抽象方法onReceive()方法。其中AMS起到了中間橋梁作用。

系統廣播:

Android系統中有很多系統廣播,比如:

Event Description Intent.ACTION_AIRPLANE_M 關閉或打開飛行模式時的廣播 Intent.ACTION_BATTERY_CH 充電狀態,或者電池的電量發生變化;//電池的充電狀態、電荷級別改變,不能通過組建聲 Intent.ACTION_BATTERY_LO 表示電池電量低 Intent.ACTION_BATTERY_OK 表示電池電量充足 Intent.ACTION_AIRPLANE_MODE_CHANGED 關閉或打開飛行模式時的廣播 Intent.ACTION_BATTERY_CHANGED 充電狀態,或者電池的電量發生變化;電池的充電狀態、電荷級別改變,不能通過組建聲明接收這個廣播,只有通過Context.registerReceiver()注冊 Intent.ACTION_BATTERY_LOW 表示電池電量低 Intent.ACTION_BATTERY_OKAY 表示電池電量充足,即從電池電量低變化到飽滿時會發出廣播 Intent.ACTION_BOOT_COMPLETED 在系統啟動完成後,這個動作被廣播一次(只有一次)。 Intent.ACTION_CAMERA_BUTTON 按下照相時的拍照按鍵(硬件按鍵)時發出的廣播 Intent.ACTION_CLOSE_SYSTEM_DIALOGS 當屏幕超時進行鎖屏時,當用戶按下電源按鈕,長按或短按(不管有沒跳出話框),進行鎖屏時,android系統都會廣播此Action消息 Intent.ACTION_CONFIGURATION_CHANGED 設備當前設置被改變時發出的廣播(包括的改變:界面語言,設備方向,等,請參考Configuration.java) Intent.ACTION_DATE_CHANGED 設備日期發生改變時會發出此廣播 Intent.ACTION_DEVICE_STORAGE_LOW 設備內存不足時發出的廣播,此廣播只能由系統使用,其它APP不可用 Intent.ACTION_DEVICE_STORAGE_OK 設備內存從不足到充足時發出的廣播,此廣播只能由系統使用,其它APP不可用 Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE 移動APP完成之後,發出的廣播(移動是指:APP2SD) Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE 正在移動APP時,發出的廣播(移動是指:APP2SD) Intent.ACTION_GTALK_SERVICE_CONNECTED Gtalk已建立連接時發出的廣播 Intent.ACTION_GTALK_SERVICE_DISCONNECTED Gtalk已斷開連接時發出的廣播 Intent.ACTION_HEADSET_PLUG 在耳機口上插入耳機時發出的廣播 Intent.ACTION_INPUT_METHOD_CHANGED 改變輸入法時發出的廣播 Intent.ACTION_LOCALE_CHANGED 設備當前區域設置已更改時發出的廣播 Intent.ACTION_MANAGE_PACKAGE_STORAGE 表示用戶和包管理所承認的低內存狀態通知應該開始。 Intent.ACTION_MEDIA_BAD_REMOVAL 未正確移除SD卡(正確移除SD卡的方法:設置–SD卡和設備內存–卸載SD卡),但已把SD卡取出來時發出的廣播 ,擴展介質(擴展卡)已經從 SD 卡插槽拔出,但是掛載點 (mount point) 還沒解除 (unmount) Intent.ACTION_MEDIA_BUTTON 按下”Media Button” 按鍵時發出的廣播,假如有”Media Button” 按鍵的話(硬件按鍵) Intent.ACTION_MEDIA_CHECKING 插入外部儲存裝置,比如SD卡時,系統會檢驗SD卡,此時發出的廣播? Intent.ACTION_MEDIA_EJECT 已拔掉外部大容量儲存設備發出的廣播(比如SD卡,或移動硬盤),不管有沒有正確卸載都會發出此廣播, 用戶想要移除擴展介質(拔掉擴展卡)。 Intent.ACTION_MEDIA_MOUNTED 插入SD卡並且已正確安裝(識別)時發出的廣播, 擴展介質被插入,而且已經被掛載。 Intent.ACTION_MEDIA_NOFS 拓展介質存在,但使用不兼容FS(或為空)的路徑安裝點檢查介質包含在Intent.mData領域。 Intent.ACTION_MEDIA_REMOVED 外部儲存設備已被移除,不管有沒正確卸載,都會發出此廣播, 擴展介質被移除。 Intent.ACTION_MEDIA_SCANNER_FINISHED 廣播:已經掃描完介質的一個目錄 Intent.ACTION_MEDIA_SCANNER_SCAN_FILE 請求媒體掃描儀掃描文件並將其添加到媒體數據庫。 Intent.ACTION_MEDIA_SCANNER_STARTED; 廣播:開始掃描介質的一個目錄 Intent.ACTION_MEDIA_SHARED 廣播:擴展介質的掛載被解除 (unmount),因為它已經作為 USB 大容量存儲被共享。 Intent.ACTION_MEDIA_UNMOUNTED 廣播:擴展介質存在,但是還沒有被掛載 (mount) Intent.ACTION_PACKAGE_ADDED 成功的安裝APK之後//廣播:設備上新安裝了一個應用程序包。//一個新應用包已經安裝在設備上,數據包括包名(最新安裝的包程序不能接收到這個廣播) Intent.ACTION_PACKAGE_CHANGED; 一個已存在的應用程序包已經改變,包括包名 Intent.ACTION_PACKAGE_DATA_CLEARED 清除一個應用程序的數據時發出的廣播(在設置--應用管理--選中某個應用,之後點清除數據時?)//用戶已經清除一個包的數據,包括包名(清除包程序不能接收到這個廣播) Intent.ACTION_PACKAGE_INSTALL 觸發一個下載並且完成安裝時發出的廣播,比如在電子市場裡下載應用? Intent.ACTION_PACKAGE_REMOVED 成功的刪除某個APK之後發出的廣播, 一個已存在的應用程序包已經從設備上移除,包括包名(正在被安裝的包程序不能接收到這個廣播) Intent.ACTION_PACKAGE_REPLACED 替換一個現有的安裝包時發出的廣播(不管現在安裝的APP比之前的新還是舊,都會發出此廣播?) Intent.ACTION_PACKAGE_RESTARTED 用戶重新開始一個包,包的所有進程將被殺死,所有與其聯系的運行時間狀態應該被移除,包括包名(重新開始包程序不能接收到這個廣播) Intent.ACTION_POWER_CONNECTED 插上外部電源時發出的廣播 Intent.ACTION_POWER_DISCONNECTED 已斷開外部電源連接時發出的廣播 Intent.ACTION_REBOOT 重啟設備時的廣播 Intent.ACTION_SCREEN_OFF 屏幕被關閉之後的廣播 Intent.ACTION_SCREEN_ON 屏幕被打開之後的廣播 Intent.ACTION_SHUTDOWN 關閉系統時發出的廣播 Intent.ACTION_TIMEZONE_CHANGED 時區發生改變時發出的廣播 Intent.ACTION_TIME_CHANGED 時間被設置時發出的廣播 Intent.ACTION_TIME_TICK 廣播:當前時間已經變化(正常的時間流逝), 當前時間改變,每分鐘都發送,不能通過組件聲明來接收,只有通過Context.registerReceiver()方法來注冊 Intent.ACTION_UID_REMOVED 一個用戶ID已經從系統中移除發出的廣播 Intent.ACTION_UMS_CONNECTED 設備已進入USB大容量儲存狀態時發出的廣播? Intent.ACTION_UMS_DISCONNECTED 設備已從USB大容量儲存狀態轉為正常狀態時發出的廣播? Intent.ACTION_WALLPAPER_CHANGED 設備牆紙已改變時發出的廣播

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved