廣播接收器(Broadcast Receiver),是我們接觸到的第二個組件。Broadcast(廣播)是一種廣泛應(yīng)用在應(yīng)用程序之間傳輸信息的機制,而BroadcastReceiver(廣播接收器)則是用于接收來自系統(tǒng)和應(yīng)用的廣播對并對其進行響應(yīng)的組件。Android提供了一套完整的API,允許應(yīng)用程序自由地發(fā)送和接收廣播。其中發(fā)送廣播的方法就是使用Intent,而接收廣播就需要使用廣播接收器了。

廣播的類型
在介紹廣播接收器之前,我們先來具體介紹一下廣播。Android里面廣播就類似于現(xiàn)實生活里面的廣播。當我們需要傳達一些信息給很多人聽的時候,我們就會使用廣播,而在程序里面也是同樣的道理,除此以外,它不僅能夠給自己的程序發(fā)送廣播,還能夠給其他的程序發(fā)送廣播。
Android中的廣播主要可以分為兩種類型:標準廣播和有序廣播。
-
標準廣播
標準廣播是一種完全異步執(zhí)行的廣播,在廣播發(fā)出之后,幾乎所有的廣播接收器都會接受到這個廣播,因此標準廣播的效率是很高的。

-
有序廣播
有序廣播是一種同步執(zhí)行的廣播,在廣播發(fā)出之后,同一時刻只會有一個廣播接收器能夠收到這條廣播,當這個廣播接收器中的邏輯執(zhí)行完畢之后,這條廣播才能夠被繼續(xù)傳遞。所以此時的廣播接收器是有先后順序的。

接收廣播的方法
廣播接收器就是用來接收廣播,它可以對它需要的廣播進行注冊,這樣當有相應(yīng)的廣播發(fā)出時,它就能夠接收到該廣播。注冊廣播的方式一般有2種:動態(tài)注冊和靜態(tài)注冊。下面分別來看一看吧。
1.動態(tài)注冊
動態(tài)注冊簡單來說其實就是在代碼中進行使用registerReceiver()方法來為廣播接收器進行注冊。先創(chuàng)建一個空項目,然后修改主代碼:
package com.example.yzbkaka.myapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
IntentFilter intentFilter; //放置廣播的“容器”
NetworkChangeReceiver networkChangeReceiver; //廣播接收器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
networkChangeReceiver = new NetworkChangeReceiver();
intentFilter.addAction("android.net.com.CONNECTIVITY.CHANGE");
registerReceiver(networkChangeReceiver,intentFilter); //注冊廣播
}
@Override
protected void onDestroy(){
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
class NetworkChangeReceiver extends BroadcastReceiver{ //廣播接收器繼承自BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent) { //添加邏輯
Toast.makeText(MainActivity.this, "get a broadcast", Toast.LENGTH_SHORT).show();
}
}
}
這里我們首先是要創(chuàng)建一個內(nèi)部類NetworkChangeReceiver并讓它繼承BroadcastReceiver 然后我們就在它的onReceive()的方法中來添加邏輯。接著看到上面的主代碼,我們先是新建一個IntentFilter的實例,這個實例是用來存放廣播的,然后我們對它使用addAction()的方法來添加廣播,這里添加的廣播是系統(tǒng)自帶的廣播,主要是用來判斷網(wǎng)絡(luò)變化的。然后我們就使用registerReceiver()的方法來對廣播進行注冊,這里需要的兩個參數(shù)就是我們的廣播接收器和intentFilter了。
需要注意的是使用動態(tài)的方法注冊的廣播必須要手動取消注冊才行,我們在onDestroy()的方法中使用unregisterReceiver()來進行取消注冊。
2.靜態(tài)注冊
靜態(tài)注冊的主要思路就是在AndroidManifest.xml中來進行注冊。我們先創(chuàng)造一個新的類,修改代碼:
package com.example.yzbkaka.myapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "this is bootcompletereceiver", Toast.LENGTH_SHORT).show();
}
}
接著我們到AndroidManifest.xml來為接收器進行注冊:
<receiver
android:name=".BootCompleteReceiver"
android:enable="true"
android:exported="true">
</receiver>
我們在<application>的標簽類添加<receiver>來進行注冊,這里的android:enable屬性是指是否啟用這個接收器,而android:exported屬性是指是否允許這個廣播接收器接收本程序以外的廣播。
接著我們就需要來為廣播接收器添加廣播了,還是在AndroidManifest.xml中修改:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.yzbkaka.myapplication">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".BootCompleteReceiver"
android:enable="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
</manifest>
因為在Android系統(tǒng)中使用某些比較隱秘的廣播時需要我們來聲明權(quán)限,所以我們先在開頭中聲明一下權(quán)限,使用的是<uses-permission>的標簽來進行添加。之后我們在<receiver>里面使用<intent-filter>標簽來添加廣播,這一條廣播是當手機開機時系統(tǒng)會自動發(fā)布的廣播,不需要我們來手動發(fā)送。到這里我們就可以使用我們的廣播接收器了。
靜態(tài)注冊的方法看起來是要比動態(tài)注冊的方法操作要復(fù)雜一些,但是它卻能夠在程序啟動之前就能夠接收到廣播,因為動態(tài)注冊的方法實在onCreate()中進行的,所以動態(tài)注冊的廣播接收器必須當活動被創(chuàng)建起來之后才能夠接收到廣播。
發(fā)送廣播
前面我們使用的例子中接收到的廣播都是系統(tǒng)內(nèi)置的廣播,也就是說這些廣播能都在某些情況下由系統(tǒng)自動的發(fā)送。但是我們也可以自定義廣播來進行發(fā)送。
1.發(fā)送標準廣播
前面說過,標準廣播就是可以被所有的廣播接收器接收。下面我們就來發(fā)送標準廣播吧。
還是先創(chuàng)建一個空項目,然后新建一個廣播接收器:
package com.example.yzbkaka.sendbroadcastpractice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "get a broadcast", Toast.LENGTH_SHORT).show();
}
}
還是比較容易理解的代碼,這里就不多說了。接著是注冊廣播接收器:
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.example.broadcast.MY_BROADCAST"/>
</intent-filter>
</receiver>
在注冊的時候我們是自定義了一條叫做com.example.broadcast.MY_BROADCAST的廣播,到時候我們的廣播接收器就會接收這樣一條廣播。然后我們?yōu)槲覀兊闹骰顒犹砑右粋€按鈕,最后修改主代碼:
package com.example.yzbkaka.sendbroadcastpractice;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button send = (Button)findViewById(R.id.button1);
final Intent intent = new Intent("com.example.broadcast.MY_BROADCAST");
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendBroadcast(intent); //發(fā)送廣播
}
});
}
}
我們這里先是將廣播存放在intent當中,然后就是將intent使用sendBroadcast()方法來進行發(fā)送。
運行程序,然我們點擊按鈕的時候就會發(fā)送廣播,而在程序的下方就會出現(xiàn)一跳短消息提示語句,說明我們的接收器成功接收到了廣播。
2.發(fā)送有序廣播
知道了如何發(fā)送標準廣播,下面就來看一看如何發(fā)送有序廣播吧。
我們直接使用上面的項目,前面的代碼都不變,我們直接修改主代碼:
package com.example.yzbkaka.sendbroadcastpractice;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button send = (Button)findViewById(R.id.button1);
final Intent intent = new Intent("com.example.broadcast.MY_BROADCAST");
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendOrderedBroadcast(intent,null); //有序發(fā)送廣播的方法
}
});
}
}
這里我們是直接修改發(fā)送廣播的方法,改成使用sendOrderedBroadcast()方法來進行發(fā)送,這個方法需要2個參數(shù):第一個就是存儲了廣播的intent;第二個就是直接使用默認的null即可。
有序廣播的特點是必須要按照廣播接收器的優(yōu)先級來被捕獲,即優(yōu)先級越高的廣播接收器,就能夠越在前面接收廣播。所以我們接下來就來修改廣播接收器的優(yōu)先級,打開AndroidManifest.xml,修改代碼:
<intent-filter android:priority="100">
<action android:name="com.example.broadcast.MY_BROADCAST"/>
</intent-filter>
使用priority的屬性來設(shè)置廣播接收器的優(yōu)先級,這里我們設(shè)置為100。之后如果有多個廣播接收器,我們就可以手動的設(shè)置它們的優(yōu)先級來為它們進行排序。
當然,優(yōu)先級高的廣播接收器也可以執(zhí)行不讓廣播繼續(xù)傳送的操作,即廣播傳到它這里以后就不會再傳書下去了,我們直接在onCreate()里面添加abortBroadcase()方法就能夠阻斷廣播的傳輸了。
使用本地廣播
我們之前發(fā)送的廣播(包括系統(tǒng)廣播和自定義廣播)都是在系統(tǒng)內(nèi)全局發(fā)送的,即所有的程序都能夠接收這些廣播。但是有些情況下我們不想讓其他的程序收到我們的廣播時,我們就可以選擇發(fā)送本地廣播。
新建項目,添加一個按鈕,然后直接修改主代碼:
package com.example.yzbkaka.localbroadcasttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
IntentFilter intentFilter;
LocalReceiver localReceiver;
LocalBroadcastManager localBroadcastManager; //創(chuàng)建管理器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button send = (Button)findViewById(R.id.button1);
localBroadcastManager = LocalBroadcastManager.getInstance(this);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.broadcast.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent); //發(fā)送廣播
}
});
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcast.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver,intentFilter); //注冊廣播接收器
}
class LocalReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "get local broadcast", Toast.LENGTH_SHORT).show();
}
}
}
這里我們是采用動態(tài)注冊的方法來實現(xiàn)的,因為我們想要的是發(fā)送不讓其他程序接收到的廣播,如果采用靜態(tài)的注冊方法,則在我們活動創(chuàng)建之前就有了廣播,這和我們想要的是不同的。接著我們就是創(chuàng)建一個LocalBroadcastManager的實例,我們發(fā)送本地廣播主要就是依靠它來完成的。然后就是調(diào)用LocalBroadcastManager實例的方法來進行發(fā)送和注冊。