1. 程式人生 > >詳解廣播機制

詳解廣播機制

廣播的型別

廣播型別分為有序廣播和標準廣播。標準廣播是一種完全非同步執行的廣播,在廣播發出之後,所有的廣播接收器幾乎在同一時間接收到這條廣播資訊,沒有先後順序可言,無法被截斷。有序廣播是同步執行的廣播,同一時間只有一個廣播接收器可以接收這條訊息,只有當廣播接收器中的邏輯執行完畢,廣播才能繼續傳遞。此時廣播接收器是有先後順序的,前面的廣播接收器還可以截斷正在傳遞的廣播。

動態註冊廣播:

需要在程式碼中註冊廣播

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.傳送本地廣播比起傳送系統全域性廣播將會更加高效。