詳解廣播機制
廣播的型別
廣播型別分為有序廣播和標準廣播。標準廣播是一種完全非同步執行的廣播,在廣播發出之後,所有的廣播接收器幾乎在同一時間接收到這條廣播資訊,沒有先後順序可言,無法被截斷。有序廣播是同步執行的廣播,同一時間只有一個廣播接收器可以接收這條訊息,只有當廣播接收器中的邏輯執行完畢,廣播才能繼續傳遞。此時廣播接收器是有先後順序的,前面的廣播接收器還可以截斷正在傳遞的廣播。
動態註冊廣播:
需要在程式碼中註冊廣播
public class MainActivity extends AppCompatActivity { private IntentFilter intentFilter; private NetworkChangeReceiver networkChangeReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intentFilter = new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_ CHANGE"); networkChangeReceiver = new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver,intentFilter); } @Override protected void onDestroy(){ super.onDestroy(); unregisterReceiver(networkChangeReceiver); } private class NetworkChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent){ ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if(networkInfo != null && networkInfo.isAvailable()){ Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();; }else{ Toast.makeText(context,"network is unavailable",Toast.LENGTH_SHORT).show(); } } } }
在MainActivity中定義一個內部類NetworkChangeReceiver,該類繼承自BroadcastReceiver,並重寫onReceive()方法。每當網路狀態發生變化時,執行onReceive()方法。在onCreate()中建立IntentFilter 例項,為它新增值為android.net.conn.CONNECTIVITY_CHANGE的action,當網路狀態發生改變時,系統發出的就是一條值為android.net.conn.CONNECTIVITY_CHANGE的廣播,廣播接收器想要監聽什麼廣播只需要新增相應的action。接下來建立一個NetworkChangeReceiver的例項,然後呼叫registerReceiver()方法進行註冊,將NetworkChangeReceiver和IntentFilter 例項傳入。為防止記憶體洩露,在onDestroy()方法呼叫unregisterReceiver()方法實現取消註冊廣播功能。在onReceive()方法中,通過getSystemService()方法得到了ConnectivityManager的例項,這是個系統服務類,專門用於管理網路連線,然後呼叫getActiveNetworkInfo()方法可以得到NetworkInfo的例項,接著呼叫NetworkInfo的isAvailable()方法,就可以判斷是否有網路。最後需要在AndroidManifest.xml檔案宣告許可權訪問網路狀態。
靜態註冊廣播
靜態註冊廣播可以在程式未啟動時便能接收到廣播。這裡我們準備讓程式接收一條開機廣播,當收到這條廣播時就可以在onReceive()方法裡執行相應的邏輯,從而實現開機啟動的功能。新建一個BootCompleteReceiver繼承自BroadcastReceiver,程式碼如下所示:
public class BootCompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show(); } }
先在AndroidManifest.xml檔案新增如下許可權
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
然後在application標籤中新增標籤註冊廣播接收器,在標籤中加入想要接收的廣播。由於Android系統啟動完成後會發出一條值為android.intent.action.BOOT_COMPLETED的廣播,因此我們在這裡添加了相應的action。
<receiver android:name=".BootCompleteReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
傳送標準廣播
首先定義一個廣播接收器
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
}
}
然後在AndroidManifest.xml對這個廣播接收器進行註冊,讓其接收一條值為com.example.broadcasttest. MY_BROADCAST的廣播
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="com.example.broadcasttest. MY_BROADCAST"/>
</intent-filter>
</receiver>
然後在MainActivity構建Intent物件,並吧要傳送的廣播的值傳入,然後呼叫context的sendBroadcast()方法將廣播發送出去。
public class MainActivity extends Activity {
……
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.broadcasttest. MY_BROADCAST");
sendBroadcast(intent);
}
});
}
}
傳送有序廣播
傳送廣播方式區別於標準廣播,使用如下程式碼,第二個引數是一個與許可權相關的字串
sendOrderedBroadcast(intent, null);
有序廣播可以通過設定廣播接收器的優先順序,改變先後順序,還可以將廣播截斷,主要在註冊中設定,在AndroidManifest.xml中的廣播接收器中加入如下程式碼
<intent-filter android:priority="100" >
同時也可以截斷廣播,只需要在廣播接收器的onReceive()方法中加入如下程式碼
abortBroadcast();
使用本地廣播
首先是通過LocalBroadcastManager的getInstance()方法得到了它的一個例項,然後在註冊廣播接收器的時候呼叫的是LocalBroadcastManager的registerReceiver()方法,在傳送廣播的時候呼叫的是LocalBroadcastManager的sendBroadcast()方法,僅此而已。這裡我們在按鈕的點選事件裡面發出了一條com.example.broadcasttest. LOCAL_BROADCAST廣播,然後在LocalReceiver裡去接收這條廣播
public class LocalBroadcastActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private LocalBroadcastManager localBroadcastManager;
private LocalReceiver localReceiver;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.local_activity);
localBroadcastManager = LocalBroadcastManager.getInstance(this);// 獲取例項
Button btn = (Button)findViewById(R.id.button2);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent);// 傳送本地廣播
}
});
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver,intentFilter);// 註冊本地廣播監聽器
}
@Override
protected void onDestroy(){
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
private class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"received local broadcast",Toast.LENGTH_SHORT).show();
}
}
}
最後我們再來盤點一下使用本地廣播的幾點優勢吧。
1.可以明確地知道正在傳送的廣播不會離開我們的程式,因此不需要擔心機密資料洩漏的問題。
2.其他的程式無法將廣播發送到我們程式的內部,因此不需要擔心會有安全漏洞的隱患。
3.傳送本地廣播比起傳送系統全域性廣播將會更加高效。