在一個IP網(wǎng)絡范圍中,最大的ip地址是被保留用作廣播地址來使用的,比如某個IP范圍是192.168.0.xxx,子網(wǎng)掩碼是255.255.255.0,那么這個網(wǎng)絡的廣播地址就是192.168.0.255.廣播數(shù)據(jù)包會被發(fā)送到同一個網(wǎng)絡上的所有端口,這樣在該網(wǎng)絡中的每臺主機都會接收到這條廣播.
1.廣播機制簡介:
發(fā)送廣播方法是之前學的intent 接收廣播的方法需要一個廣播接收器(BroadcastReceiver)
什么是標準廣播和有序廣播?
標準廣播是一種異步廣播,即在廣播發(fā)出后,幾乎所有的廣播接收器都會在同一時刻接收到這條廣播信息,他們之間沒有順序可言,廣播效率比較高,但是不能截斷.
有序廣播是一種同步執(zhí)行的廣播,在廣播發(fā)出后,同一時刻只會有一個廣播接收器接收到這條廣播的消息,當這個廣播接收器中的邏輯執(zhí)行完畢后,廣播才會繼續(xù)傳遞.
2.接收系統(tǒng)廣播
什么是系統(tǒng)廣播?
系統(tǒng)廣播比如手機開機之后會發(fā)出一條廣播,電池電量發(fā)生狀態(tài)變化會發(fā)出一條廣播,時間或時區(qū)發(fā)生改變也會發(fā)出一條廣播.
動態(tài)監(jiān)聽網(wǎng)絡變化
注冊廣播的方式分為動態(tài)注冊和靜態(tài)注冊
靜態(tài)注冊 在AndroidManifest.xml中注冊;動態(tài)注冊 在代碼中注冊.
前面我們說了應用程序發(fā)送廣播和接收廣播分別通過intent 和廣播接收器(BroadcastReceiver),那么如何新建一個廣播接收器呢??
只需要創(chuàng)建一個類,讓他繼承BoradcastReceiver,并重寫B(tài)oradcastReceiver的子方法onReceive()即可.當有廣播來時,onReceive()方法變回執(zhí)行,具體的邏輯可以在這個方法中處理.
public class MainActivity extends AppCompatActivity {
private NetworkChangeReceiver networkChangeReceiver;
private IntentFilter intentFilter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter=new IntentFilter();
?intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
?NetworkChangeReceiver networkChangeReceiver=new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver,intentFilter); ?}
@Override
?protected void onDestroy(){
?super.onDestroy();
unregisterReceiver(networkChangeReceiver); ?}
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// //直接打印Toast
Toast.makeText(context,"network is changed",Toast.LENGTH_SHORT).show();}}
}
首先看我們創(chuàng)建的NetworkChangeReceiver這個廣播接收器類,它繼承了BroadcastReceiver這個類,并重寫了這個類的onReceive方法,并在這個方法中執(zhí)行Toast()操作.
再看onCreat()方法,在這個方法中我們創(chuàng)建了一個IntentFilter實例,并給它添加了一個值為android.net.conn.CONNECTIVITY_CHANGE的action,因為網(wǎng)絡狀態(tài)發(fā)生變化時,系統(tǒng)發(fā)出的正是一條值為android.net.conn.CONNECTIVITY_CHANGE的廣播,也就是說我們的廣播接收器想要監(jiān)聽什么廣播,就在這里添加相應的action。(關(guān)于IntentFilter的用法詳情請見http://blog.csdn.net/today520/article/details/7000048 ,總的來說就是一個過濾器可以認為是intent過濾器)然后再onCreat()方法中創(chuàng)建NetworkChangeReceiver的實例,最后調(diào)用registerReceiver方法進行注冊,將NetworkChangeReceiver的實例和IntentFilter實例都傳進去,這樣NetworkChangeReceiver就會接收所有值為android.net.conn.CONNECTIVITY_CHANGE的廣播,也就實現(xiàn)了監(jiān)聽網(wǎng)絡變化的功能.
最后要記得,動態(tài)注冊的廣播接收器一定都要取消注冊才行,這里我們是在。onDestroy()方法中通過調(diào)用unregisterReceiver()方法來實現(xiàn)的。(其中unregisterReceiver()方法中傳入的是我們創(chuàng)建的這個NetworkChangeReceiver這個廣播接收器)
如果我們覺得提醒網(wǎng)絡變化不夠人性化,那么我們可以對代碼進行如下調(diào)整.
public class MainActivity extends AppCompatActivity{
........
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context,Intent intent){? ?
ConnectivityManager connectionManager==(ConnectivityManager)getSystemService(Context.CONNECTIVITY SERVICE);? ? NetworkInfo networkInfo = connectionManager.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();}
}
}}
需要注意的是:首先通過getSystemService(Context.CONNECTIVITY SERVICE);方法獲得?ConnectivityManager的實例,這個一個系統(tǒng)服務類(專門用于管理網(wǎng)絡連接的,可以通過查其源代碼發(fā)現(xiàn)返回的是Object對象,所以需要對其進行強制轉(zhuǎn)型.),然后通過調(diào)用它的getActiveNetworkInfo();方法可以判斷當前是否有網(wǎng)絡,然后加一個if語句來判斷,判斷條件是其若不為空,且存在則....否則 ?....
Android為了保護用戶的隱私和設備安全,嚴格規(guī)定:如果程序需要進行一些對用戶來說比較敏感的操作,就必須要在配置文件中聲明權(quán)限才可以,否則程序會很容易崩潰.比如這里的訪問系統(tǒng)的網(wǎng)絡狀態(tài)就是需要聲明權(quán)限的.聲明權(quán)限是在AndroidManifest.xml文件.
靜態(tài)注冊實現(xiàn)開機啟動
動態(tài)注冊廣播接收器具有很大的靈活性,可是必須要在程序啟動后才能接收的廣播,因為注冊邏輯是寫在onCreat()方法中的,靜態(tài)注冊可以實現(xiàn)讓程序在未啟動的情況下就能接收廣播.步驟如下右擊。包--New---Other-Broadcast Receiver,會彈出一個窗口
可以看到,這里我們將廣播接收器命名為BootCompleteReceiver, Exported屬性表示是否允許這個廣播接收器接收本程序以外的廣播,Enabled屬性表示是否啟用這個廣播接收器。勾選這兩個屬性,點擊Finish完成創(chuàng)建。
然后修改BootCompleteReceiver中的代碼,如下所示:
public class BootCompleteReceiver extends BroadcastReceiver{
@override
public void onReceive(Context context,Intent intent){
Toast.makeText(context, "Boot Complete",Toast.LENGTH_ LONG).show();
}}
另外,靜態(tài)的廣播接收器一定要在AndroidManifest.xml文件中注冊才可以使用,不過由于我們是使用Android Studio的快捷方式創(chuàng)建的廣播接收器,因此注冊這一步已經(jīng)被自動完成了。代開AndroidManifest.xml文件會看到一個<receiver>標簽屬性有name enabled expoorted等
它的用法其實和<activity>標簽非常相似,也是通過android:name來指定具體注冊哪一個廣播接收器,而enabled和exported屬性則是根據(jù)我們剛才勾選的狀態(tài)自動生成的。還要再給AndroidManifest.xml文件添加
才能收到開機廣播.
由于Android系統(tǒng)啟動完成后會發(fā)出一條值為android.intent.action.B00T_COMPLETED的廣播,因此我們在<intent-filter>標簽里添加了相應的action。另外,監(jiān)聽系統(tǒng)開機廣播也是需要聲明權(quán)限的,可以看到,我們使用<user-permission>標簽又加人了一條android.permission.RECEIVE_ BOOT COMPLETED權(quán)限.
發(fā)送自定義廣播
上面的內(nèi)容主要是通過廣播接收器來接收系統(tǒng)廣播,接下來我們學習一下如何在應用程序中發(fā)送自定義廣播.
發(fā)送標準廣播
發(fā)送廣播之前首先定義一個廣播接收器來接收次廣播才行,不然發(fā)出去也是白發(fā).新建一個MyBroadcastReceiver.
public class MyBroadcastReceiver extends BroadcastReceiver {
//------------發(fā)送自定義廣播------------發(fā)送標準廣播--------發(fā)送有序廣播----
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
//-------------發(fā)送有序廣播中的廣播截斷-----------
//在設置了接收廣播的優(yōu)先權(quán)之后,那么MyBroadcastReceiver便可以自己選擇是否允許廣播繼續(xù)傳遞了 //
通過abortBroadcast()方法 這個方法的意思是終止發(fā)送的意思
abortBroadcast();
} }
這里當MyBroadcastReceiver收到自定義廣播時,就會彈出received in MyBroadcastReceiver的提示
在AndroidMinifest.xml文件中修改
? ?
讓MyBroadcastReceiver接收一條值為com.exampte.broadcasttest.MY_BROADCAST的廣播,因此待會兒在發(fā)送廣播的時候,我們就需要發(fā)出這樣的一條廣播。
首先構(gòu)造了一個Intent對象,并把要發(fā)送的廣播的值傳入,然后調(diào)用了Context的sendBroadcast()方法將廣播發(fā)送出去,這樣所有監(jiān)聽com.example.broadcasttest.MY_BROADCAST這條廣播接收器都會收到消息.
在這里要和IntentFilter對比一下,在之前我們說了用intent發(fā)送消息,用廣播接收器接收接收廣播,IntentFilter是采用addAction()的方法將網(wǎng)絡狀態(tài)變化添加進去,Intent直接將要發(fā)送的廣播的值傳入其構(gòu)造方法中,然后調(diào)用context的sendBroadcast()方法來發(fā)送廣播,這樣所有監(jiān)聽com.example.broadcasttest.MY_BROADCAST這條廣播接收器(例如MyBroadcastReceiver)都會收到消息.
提一個問題:IntentFilter和AndroidMinifest.xml文件中intent-filter標簽有什么關(guān)系???
發(fā)送有序廣播和標準廣播基本上一個套路,只不過在MainActivity中將sendBroadcast(intent)改成了sendOrderBroadcast(intent,null)
想要發(fā)送有序廣播最好還是多建幾個廣播接收器,這樣效果比較好.比如再建一個AnotherBroadcastReceiver,同樣也是重寫onReceive()方法,然后在AndroidMinifest.xml文件中修改<intent-filter>標簽,將標簽中的action的名字指定為com.example.broadcasttest.MY_BROADCAST因為只有將AnotherBroadcastReceiver也接收這條廣播,現(xiàn)在運行BroadcastTest2項目將這個程序安裝到模擬器上,然后重新回到BroadcastTest項目的主界面,并點擊一下Send Broadcast按鈕,就會分別彈出兩次提示信息.
給廣播接收器設定先后順序在AndroidMinifest.xml中的intent-filter標簽中加上 ?android:priorty="100"即可!(android:priorty屬性給廣播接收器設置了優(yōu)先級,優(yōu)先級比較高的廣播接收器可以先收到廣播)-----獲得了接收廣播的優(yōu)先權(quán)之后 因為我們這次寫的代碼中MyBroadcastReceiver的優(yōu)先級要高于AnotherBroadcastReceiver的優(yōu)先級,所以在MyBroadCastReceiver.java中加上aborBroadcasr()方法(該方法的意思是終止發(fā)送廣播即后面一個廣播接收器AnotherBroadcastReceiver將收不到廣播消息即我們所說的廣播截斷)
使用本地廣播
系統(tǒng)全局廣播容易引起安全性問題,因為發(fā)出的廣播可以被任何應用程序接收到,并且我們也可以接受來自于其他任何應用程序的廣播.
本地廣播機制:使用這個廣播機制發(fā)出去的廣播只能夠在應用程序的內(nèi)部進行傳遞,并且廣播接收器也只能接受來自本應用程序發(fā)出的廣播
本地廣播的用法和我們之前說的動態(tài)注冊監(jiān)聽網(wǎng)絡變化差不多,只不過本地廣播用到了一個LocalBroadcastManager來對廣播進行管理,并提供了發(fā)送廣播和接收廣播的方法.
我認為共同的套路都是新建一個廣播接收器(LocalBroadcastReceiver),然后重寫B(tài)roadcastReceiver的onReceive方法
新建一個IntentFilter對象然后用IntentFilter.addaction(要發(fā)送的廣播的值)
IntentFilter和intent LocalBroadcastReceiver都要新建實例
無非就是多了:
1.采用LocalBroadcastManager.getInstance()方法來獲得LocalBroadcastManager的實例
2.在構(gòu)建Intent對象,并把要發(fā)送的廣播的值植入inent對象之后,采用LocalBroadcastManager.sendBroadcast(intent)方法來發(fā)送廣播
3.注冊廣播接收器的時候采用的是LocalBroadcastManager的registerReceiver()方法(方法中的參數(shù)是IntentFilter和localBroadcastReceiver)
4.取消注冊廣播接收器時是LocalBroadcastManager的unregisterReceiver()方法
本地廣播無法通過靜態(tài)注冊的方式來接收!!!要注意!!