1. 程式人生 > >一篇就夠了系列之BroadcastReceiver全解析

一篇就夠了系列之BroadcastReceiver全解析

前言:

上一篇一篇就夠了系列之Service全解析,介紹了Android四大元件的Service,本篇繼續來介紹Android四大元件之BroadcastReceiver(廣播接收者)。

Broadacast(廣播):

首先,我們應該清楚在Android系統中,Broadcast(廣播)是什麼?

廣播是一種可以在不同App之間,類似訂閱者模式(publish-subscribe design pattern)的資訊交流的方式。比如當系統的 開機,電量的變化 都會發送廣播,對這些廣播進行了訂閱的廣播接收者此時會接收到相關的通知然後就可以在其中做出相應的處理操作。這些系統的廣播很有用,但是你也要十分小心不要濫用廣播這種方式,會有導致系統執行緩慢的可能。

分類

  • 普通廣播(Normal Broadacast)
  • 有序廣播(Order Broadcast)
  • 本地廣播(LocalBroadcast)
  • 粘性廣播(StickyBroadcast):已經廢棄了該API,不做討論。

英文原文:

  • The sendBroadcast(Intent) method sends broadcasts to all receivers in an undefined order. This is called a Normal Broadcast. This is more efficient, but means that receivers cannot read results from other receivers, propagate data received from the broadcast, or abort the broadcast.

  • The sendOrderedBroadcast(Intent, String) method sends broadcasts to one receiver at a time. As each receiver executes in turn, it can propagate a result to the next receiver, or it can completely abort the broadcast so that it won’t be passed to other receivers. The order receivers run in can be controlled with the android:priority attribute of the matching intent-filter; receivers with the same priority will be run in an arbitrary order.

  • The LocalBroadcastManager.sendBroadcast method sends broadcasts to receivers that are in the same app as the sender. If you don’t need to send broadcasts across apps, use local broadcasts. The implementation is much more efficient (no interprocess communication needed) and you don’t need to worry about any security issues related to other apps being able to receive or send your broadcasts.

普通廣播
一般的廣播,即傳送一個廣播後,所有監聽該廣播的接收者都可以接收到,同時接收並且不能阻止別人接收
程式碼為:

sendBroadcast(new Intent("com.wenyi.interview.mynormalb"));

有序廣播
有序廣播比較特殊,它每次只發送到優先順序較高的接收者那裡,然後由優先順序高的接受者再傳播到優先順序低的接收者那裡,優先順序高的接收者有能力終止這個廣播。優先順序在manifest中進行設定,程式碼為:

sendOrderedBroadcast(new Intent("com.wenyi.interview.mynormalb"), "interview.permission.MY_BROADCAST_PERMISSION);  

或者

sendOrderedBroadcast(intent, receiverPermission, resultReceiver,
       scheduler, initialCode, initialData, initialExtras)

注意,在兩個引數的方法中,使用sendOrderedBroadcast方法傳送有序廣播時,需要一個許可權引數,如果為null則表示不要求接收者宣告指定的許可權,如果不為null,則表示接收者若要接收此廣播,需宣告指定許可權。這樣做是從安全形度考慮的,例如系統的簡訊就是有序廣播的形式,一個應用可能是具有攔截垃圾簡訊的功能,當簡訊到來時它可以先接受到簡訊廣播,必要時終止廣播傳遞,這樣的軟體就必須宣告接收簡訊的許可權。
所以我們在AndroidMainfest.xml中定義和宣告一個許可權:

    //定義
    <permission 
        android:protectionLevel="normal"
        android:name="interview.permission.MY_BROADCAST_PERMISSION"/>
    //宣告
    <uses-permission android:name="interview.permission.MY_BROADCAST_PERMISSION"/>

在七個引數的方法中:
resultReceiver :BroadcastReceiver型別,即指定最後的廣播接收器。
scheduler:Handler型別,排程自定義處理程式,用以安排 resultReceiver 回撥 ; 如果為 null 將在語境中的主執行緒舉行。
initialCode :int型別,一種結果程式碼的初始值。通常為 Activity.RESULT_OK 。這個值是 -1 ;為其他 int 型 也可以,如 0,1,2;
initialData :String型別,一種結果資料的初始值。通常情況下為空 ;
initialExtras :Bundle型別,一種結果額外的初始值。通常情況下為空;

本地廣播:即傳送的廣播只有該App可以接收到,資訊更加安全,效率更高,推薦使用。

  LocalBroadcastManager.getInstance(BroadcastActivity.this).sendBroadcast(new Intent("com.wenyi.interview.mynormalb"));

總結:通過以上可知,廣播的傳送很簡單,在Activity或者Service中直接呼叫即可,下面來看看接收者。

BroadcastReceiver(廣播接收者)

廣播接收者作為四大元件之一,使用的時候需要進行註冊,不同於其他的元件,BroadcastReceiver除了在Manifest中進行註冊外,還可以用Java程式碼直接註冊。

Manifest註冊:

manifest:

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

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

        <receiver android:name=".FourComponet.broadcast.MyReceiver1"
            >
            <intent-filter android:priority="-1000">
                <action android:name="com.wenyi.interview.mynormalb"/>
            </intent-filter>
        </receiver>

        <receiver android:name=".FourComponet.broadcast.MyReceiver2">
            <intent-filter android:priority="1000">
                <action android:name="com.wenyi.interview.mynormalb"/>
            </intent-filter>
        </receiver>

Activity:

public class BroadcastActivity extends AppCompatActivity {

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


        findViewById(R.id.normal_broadcast).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendBroadcast(new Intent("com.wenyi.interview.mynormalb"));
            }
        });

        findViewById(R.id.ordered_broadcast).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendOrderedBroadcast(new Intent("com.wenyi.interview.mynormalb"),"interview.permission.MY_BROADCAST_PERMISSION");
            }
        });
        findViewById(R.id.ordered_broadcast_2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendOrderedBroadcast(new Intent("com.wenyi.interview.mynormalb"),"interview.permission.MY_BROADCAST_PERMISSION"
                ,new MyReceiver1(),null,0,"",null);
            }
        });

    }
}

Receiver1:

public class MyReceiver1 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        Log.i("wy", "MyReceiver1    time:"+System.currentTimeMillis());
    }
}

Receiver2:

public class MyReceiver2 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        Log.i("wy", "MyReceiver2    time:"+System.currentTimeMillis());

        abortBroadcast();

    }
}

程式碼十分的簡單,主要可簡單總結為:

  1. 繼承Broadcast,重寫onReceiver方法
  2. 在manifest進行註冊,需要定義action,這是廣播的依據,有序廣播需要定義和申明許可權
  3. 普通廣播都能接收,有序廣播按照優先順序接收,可以銷燬,呼叫 abortBroadcast()方法
  4. 列印log,嘗試加深理解

Java程式碼註冊:

    @Override
    protected void onResume() {
        super.onResume();

        //動態註冊receiver的Intent過濾器和action
        IntentFilter filter = new IntentFilter();
        filter.addAction("dynamic_register");
        mMyReceiver3=new MyReceiver3();
        registerReceiver(mMyReceiver3, filter);

        Intent intent = new Intent();
        //這條廣播的標誌
        intent.setAction("dynamic_register");
        //傳送廣播
        sendBroadcast(intent);

        //動態註冊receiver的Intent過濾器和action
        IntentFilter filter1 = new IntentFilter();
        filter1.addAction("dynamic_register_2");
        mMyReceiver4=new MyReceiver4();
        manager=LocalBroadcastManager.getInstance(BroadcastActivity.this);
        manager.registerReceiver(mMyReceiver4, filter1);

        Intent intent1 = new Intent();
        //這條廣播的標誌
        intent1.setAction("dynamic_register_2");
        //傳送廣播
        manager.sendBroadcast(intent1);
    }

    @Override
    protected void onPause() {
        super.onPause();

        unregisterReceiver(mMyReceiver3);
        manager.unregisterReceiver(mMyReceiver4);
    }

說明:

  1. 程式碼進行註冊,一般是在onResume中進行註冊,onPause中進行解註冊,一定要解註冊。
  2. 註冊程式碼邏輯也就是設定filter的action,然後呼叫註冊方法。
  3. 本地廣播只能這樣進行動態註冊,註冊的呼叫物件是LocalBroadcastManager,解註冊也是如此。

最後:

  • onReceiver中不能做耗時操作,超過十秒鐘會異常
  • 生命週期十分簡單,建立,執行,結束

常見的系統廣播:

1.開機啟動服務

action:android.intent.action.BOOT_COMPLETED
category :android.intent.category.DEFAULT
同時申明許可權:

2.網路狀態變化

action:android.net.conn.CONNECTIVITY_CHANGE
category :android.intent.category.DEFAULT
同時申明許可權:

3.電量變化

action:android.intent.action.BATTERY_CHANGED
category :android.intent.category.DEFAULT

4.監聽SD卡狀態

清單檔案中定義廣播接收者接收的型別,監聽SD卡常見的三種狀態,所以廣播接收者需要接收三種廣播

 <receiver android:name="com.itheima.sdcradlistener.SDCardReceiver">
    <intent-filter >
        <action android:name="android.intent.action.MEDIA_MOUNTED"/>
        <action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
        <action android:name="android.intent.action.MEDIA_REMOVED"/>
        <data android:scheme="file"/>
    </intent-filter>
</receiver>

5監聽應用的安裝、解除安裝、更新

原理:應用在安裝解除安裝更新時,系統會發送廣播,廣播裡會攜帶應用的包名
清單檔案定義廣播接收者接收的型別,因為要監聽應用的三個動作,所以需要接收三種廣播

<receiver android:name="com.itheima.app.AppReceiver">
    <intent-filter >
        <action android:name="android.intent.action.PACKAGE_ADDED"/>
        <action android:name="android.intent.action.PACKAGE_REPLACED"/>
        <action android:name="android.intent.action.PACKAGE_REMOVED"/>
        <data android:scheme="package"/>
    </intent-filter>
</receiver>

歡迎閱讀其他系列文章: