Android 第十九课 大喇叭--广播机制----动态注册监听网络变化与静态注册实现开机启动
1、廣播機(jī)制簡介:
因?yàn)锳ndroid中的每個(gè)應(yīng)用程序都可以對自己感興趣的廣播盡心注冊,這樣程序只會(huì)接收自己所關(guān)心的廣播內(nèi)容,
這些廣播來自于系統(tǒng)的,也可能來自于其他應(yīng)用程序的。Android提供了一套完整的API,允許應(yīng)用程序自己地發(fā)送和
接收廣播,發(fā)送廣播的方法就是借助Intent,而接收廣播的方法,要引入廣播接收器(Broadcast Receiver)。
廣播分為兩類,標(biāo)準(zhǔn)廣播和有序廣播,
標(biāo)準(zhǔn)廣播(Normal broadcase)是一種完全異步執(zhí)行的廣播,再廣播發(fā)出去以后,
所有的廣播接收器機(jī)會(huì)會(huì)在同一時(shí)刻接收到這條廣播消息,因此它們之間沒有任何先后順序,這樣的廣播的效率會(huì)比較高
但同時(shí)也意味著它是無法被截?cái)嗟摹!?
有序廣播(Ordered broadcasts)是一種同步執(zhí)行的廣播,在廣播發(fā)出去之后,同一時(shí)刻只會(huì)有一個(gè)廣播接收器能
夠收到這條廣播消息,當(dāng)這個(gè)廣播接收器中的邏輯執(zhí)行完畢后,廣播才會(huì)繼續(xù)傳遞。優(yōu)先級(jí)高的廣播就可以先接收廣播消息,并且還可以截?cái)嗾趥鬟f的廣播。
二、接收系統(tǒng)廣播
Android內(nèi)置了很多系統(tǒng)級(jí)別的廣播,我們可以在應(yīng)用程序中通過監(jiān)聽這些廣播來得到各種系統(tǒng)的狀態(tài)信息。
1、動(dòng)態(tài)注冊監(jiān)聽網(wǎng)絡(luò)變化
廣播接收器可以自由的對自己感興趣的廣播進(jìn)行注冊,當(dāng)有相應(yīng)的廣播發(fā)出時(shí),廣播接收器就可以收到該廣播,并在
內(nèi)部處理相應(yīng)的邏輯。注冊廣播的方式一般有兩種 ,動(dòng)態(tài)注冊和靜態(tài)注冊,所謂動(dòng)態(tài)注冊是在代碼中注冊,靜態(tài)注冊在
AndroidManifest.xml中注冊。
如何創(chuàng)建一個(gè)廣播接收器呢? 只需要新建一個(gè)類,讓它繼承自BroadcastReceiver,并重寫父類的onReceive()方法
就行了。這樣當(dāng)有廣播到來時(shí), onReceive()方法就會(huì)得到執(zhí)行,具體的邏輯就會(huì)在這個(gè)方法中處理。
我們先通過 動(dòng)態(tài)注冊的方式去編寫一個(gè)能夠監(jiān)聽網(wǎng)絡(luò)變化的程序,學(xué)習(xí)一下廣播接收器的基本用法。
新建項(xiàng)目BroadcastTest。然后,修改MainActivity中的代碼:
package com.example.broadcasttest;
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 {
? ??
? ??
? ? private IntentFilter intentfiletr;
? ? private NetworkChangeReceiver networkChangeReceiver;
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_main);
? ? ? ? intentfiletr = new IntentFilter();
? ? ? ? intentfiletr.addAction("android.net.conn.CONNECTIVITY_CHANGE");
? ? ? ? networkChangeReceiver = new NetworkChangeReceiver();
? ? ? ? registerReceiver(networkChangeReceiver,intentfiletr);
? ? }
? ? @Override
? ? protected void onDestroy() {
? ? ? ? super.onDestroy();
? ? ? ? unregisterReceiver(networkChangeReceiver);
? ? }
? ? class NetworkChangeReceiver extends BroadcastReceiver{
? ? ? ? @Override
? ? ? ? public void onReceive(Context context, Intent intent) {
? ? ? ? ? ? Toast.makeText(context,"network changes",Toast.LENGTH_SHORT).show();
? ? ? ? }
? ? }
}
我們在MainActivity中定義了一個(gè)內(nèi)部類 NetworkChangeReceiver,這個(gè)類是繼承自BroadcastReceiver的,并重寫了
父類的 onReceive()。 這樣每當(dāng)網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí),onReceive()方法都會(huì)得到執(zhí)行,這里只是簡單的使用Toast提示了一段文本信息。
在onCreat()方法,我們首先創(chuàng)建了一個(gè)IntenFilter的實(shí)例,并給它添加了一個(gè)android.net.conn.CONNECTIVITY_CHANGE的
廣播,也就是說當(dāng)我們想要監(jiān)聽什么樣的廣播,就在這里添加相應(yīng)的action。接下來,我們創(chuàng)建一個(gè)NetworkChangeReceiver
的實(shí)例,然后調(diào)用registerReceiver()方法進(jìn)行注冊,將NetworkChangeReciver的實(shí)例和IntentFilter的實(shí)例都傳了進(jìn)去
這樣,NetworkChangeReceiver就會(huì)收到所有值為android.conn.CONNECTIVITY_CHANGE的廣播。也就實(shí)現(xiàn)了監(jiān)聽網(wǎng)絡(luò)
變化的功能。
最后,動(dòng)態(tài)注冊的廣播接收器一定要取消注冊才行。我們是在onDestroy()方法中通過調(diào)用unregisterReceiver()來實(shí)現(xiàn)。
總結(jié):
如何創(chuàng)建一個(gè)廣播接收器呢?廣播接收器如何接收廣播呢?
1、只需要新建一個(gè)類,讓它繼承自BroadcastReceiver,并重寫父類的onReceive()方法
就行了。這樣當(dāng)有廣播到來時(shí),onReceiver方法就會(huì)得到執(zhí)行,具體的邏輯就會(huì)在這個(gè)方法中處理。然后創(chuàng)建這個(gè)類的
實(shí)例,調(diào)用其registerReceive()方法進(jìn)行注冊,最后也可以在onDestroy()方法取消注冊。
2、發(fā)送廣播的方法是借助Intent。怎么接收廣播呢?通過創(chuàng)建一個(gè)IntentFilter的實(shí)例,往里面添加相應(yīng)的action,
就可以接收對應(yīng)的廣播。
運(yùn)行代碼之后,,在注冊完成的時(shí)候,會(huì)收到一條廣播,然后按下Home鍵,回到主頁面,接著打開Setting程序->
Data usage 進(jìn)入到數(shù)據(jù)使用詳情界面,然后嘗試著開關(guān)Cellular data 按鈕來啟動(dòng)和禁用網(wǎng)絡(luò),看到有Toast提醒網(wǎng)絡(luò)
發(fā)生了變化。
最后可以準(zhǔn)確告訴用戶當(dāng)前是有網(wǎng)絡(luò)還是無網(wǎng)絡(luò),我們進(jìn)一步優(yōu)化代碼:
package com.example.broadcasttest;import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast;public class MainActivity extends AppCompatActivity {private IntentFilter intentfiletr;private NetworkChangeReceiver networkChangeReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);intentfiletr = new IntentFilter();intentfiletr.addAction("android.net.conn.CONNECTIVITY_CHANGE");networkChangeReceiver = new NetworkChangeReceiver();registerReceiver(networkChangeReceiver,intentfiletr);}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(networkChangeReceiver);}class NetworkChangeReceiver extends BroadcastReceiver{@Overridepublic 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();}}} }
在onReceive方法中,首先通過getSystemSerive()方法得到ConnectivityManager的實(shí)例,這是一個(gè)系統(tǒng)服務(wù)類,專門
用來管理網(wǎng)絡(luò)連接的。然后調(diào)用它的getAcitiveNetworkInfo()方法得到NetworkInfo的實(shí)例,接著調(diào)用NetworkInfo的
isAvailable()方法,就可以判斷當(dāng)前是否有網(wǎng)絡(luò)了,最后我們還是通過Toast的方式對用戶進(jìn)行提示。
Android系統(tǒng)為了保護(hù)用戶設(shè)備的安全和隱私,做了嚴(yán)格的規(guī)定,如何程序需要做一些對用戶來說比較敏感的操作,就必須在
配置文件中聲明權(quán)限才可以,否則程序?qū)?huì)直接崩潰。打開AndroidManifest.xml文件,在下面加入如下權(quán)限就可以訪問
系統(tǒng)網(wǎng)絡(luò)狀態(tài)了:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
? ? package="com.example.broadcasttest">
? ? ......
? ? <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
......
</manifest>
Android有很多操作都是需要聲明權(quán)限才可以進(jìn)行的。
現(xiàn)在我們又可以重新運(yùn)行程序了。
2、靜態(tài)注冊實(shí)現(xiàn)開機(jī)啟動(dòng)
動(dòng)態(tài)注冊的廣播接收器可以自由地控制注冊與注銷,有很大的靈活性,但有一個(gè)缺點(diǎn),必須要在程序啟動(dòng)之后才能接收廣播,因?yàn)樽缘倪壿嬍菍懺趏nCreate()方法中的,可以采取靜態(tài)注冊的方式,讓程序在未啟動(dòng)的情況下接收到廣播;
我們讓程序接收一條開機(jī)廣播,當(dāng)收到這條廣播時(shí)就可以在onReceive()方法里執(zhí)行相應(yīng)的邏輯,從而實(shí)現(xiàn)開機(jī)啟動(dòng)的功能。我們右擊com.example.broadcasttest包,-->New->another-->Broadcast Receiver,將這個(gè)廣播接收器命名為BootCompleteReceiver,Exported屬性表示是否允許廣播接收器接收本程序以外的廣播,Enabled屬性表示是否啟用這個(gè)廣播接收器。勾選這兩個(gè)屬性,點(diǎn)擊Finish完成創(chuàng)建。
然后修改BootCompleteReceiver中的代碼,如下:
package com.example.broadcasttest;import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast;public class BootCompleteReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO: This method is called when the BroadcastReceiver is receiving// an Intent broadcast.Toast.makeText(context,"Boot Complete",Toast.LENGTH_SHORT).show();} }代碼很簡單,只是在onReceiver()方法中使用Toast彈出一段提示信息。
另外靜態(tài)的廣播接收器一定要在AndroidManifest.xml文件中注冊才可以使用,不過由于我們使用的是Android Studio的快捷方式創(chuàng)建的廣播接收器,因此注冊這一步已經(jīng)被自動(dòng)完成了。代開AndroidManifest.xml文件看一看,代碼如下:
可以看到在,<application>標(biāo)簽內(nèi)出現(xiàn)了一個(gè)新的標(biāo)簽<receiver>,所有靜態(tài)的廣播接收器都是在這里進(jìn)行注冊的。她的用法其實(shí)和<activity>標(biāo)簽非常相似,也是通過android:name來指定注冊具體哪一個(gè)廣播接收器,而enabled和exported屬性則是根據(jù)我們剛才勾選的狀態(tài)自動(dòng)生成的。
不過目前BootCompleteReceiver還是不能接收到開機(jī)廣播的,我們還需要對AndroidManifest.xml文件進(jìn)行修改才行,如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.broadcasttest"><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name = "android.permision.RECEIVE_BOOT_COMPLETED"/><applicationandroid: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><receiverandroid:name=".BootCompleteReceiver"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver></application></manifest>由于Android系統(tǒng)啟動(dòng)完成后會(huì)發(fā)出一條值為android.intent.action.BOOT_COMPLETED的廣播,因此我們在<intent-filter>標(biāo)簽里添加了相應(yīng)的action。另外監(jiān)聽系統(tǒng)開機(jī)廣播也是需要權(quán)限的,可以看到,我們使用<uses-permission>標(biāo)簽又加入了一條android.permission.RECEIVE_BOOT_COMPLETED權(quán)限。
我們重新運(yùn)行程序之后,就可以接收開機(jī)廣播了。
我們在廣播接收器中的onReceive()方法都只是簡單的使用Toast提示了一段文本信息,當(dāng)你真正在項(xiàng)目中使用到它的時(shí)候,就可以在里面編寫自己的邏輯。不要在onReceive()方法中添加過多的邏輯或者進(jìn)行任何的耗時(shí)操作,因?yàn)樵趶V播接收器中式不允許開啟線程的,當(dāng)onReceive()方法運(yùn)行了較長時(shí)間還沒有結(jié)束時(shí),程序就會(huì)報(bào)錯(cuò)。因此廣播接收器更多的扮演一種打開程序或其他組件的角色,比如創(chuàng)建一條狀態(tài)欄通知,或者啟動(dòng)一個(gè)服務(wù)等。
總結(jié)
以上是生活随笔為你收集整理的Android 第十九课 大喇叭--广播机制----动态注册监听网络变化与静态注册实现开机启动的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PJzhang:kali linux安装
- 下一篇: Android 第二十课 广播机制(大喇