Android 第十九課 大喇叭--廣播機制----動態注冊監聽網絡變化與靜態注冊實現開機啟動

為了便于進行 系統級別的消息通知,Android引入了一套廣播消息機制。
1、廣播機制簡介:
因為Android中的每個應用程序都可以對自己感興趣的廣播盡心注冊,這樣程序只會接收自己所關心的廣播內容,
這些廣播來自于系統的,也可能來自于其他應用程序的。Android提供了一套完整的API,允許應用程序自己地發送和
接收廣播,發送廣播的方法就是借助Intent,而接收廣播的方法,要引入廣播接收器(Broadcast Receiver)。

廣播分為兩類,標準廣播和有序廣播,
標準廣播(Normal broadcase)是一種完全異步執行的廣播,再廣播發出去以后,
所有的廣播接收器機會會在同一時刻接收到這條廣播消息,因此它們之間沒有任何先后順序,這樣的廣播的效率會比較高
但同時也意味著它是無法被截斷的。‘
有序廣播(Ordered broadcasts)是一種同步執行的廣播,在廣播發出去之后,同一時刻只會有一個廣播接收器能
夠收到這條廣播消息,當這個廣播接收器中的邏輯執行完畢后,廣播才會繼續傳遞。優先級高的廣播就可以先接收廣播消息,并且還可以截斷正在傳遞的廣播。


二、接收系統廣播
Android內置了很多系統級別的廣播,我們可以在應用程序中通過監聽這些廣播來得到各種系統的狀態信息。
1、動態注冊監聽網絡變化
廣播接收器可以自由的對自己感興趣的廣播進行注冊,當有相應的廣播發出時,廣播接收器就可以收到該廣播,并在
內部處理相應的邏輯。
注冊廣播的方式一般有兩種 ,動態注冊和靜態注冊,所謂動態注冊是在代碼中注冊,靜態注冊在
AndroidManifest.xml中注冊。

如何創建一個廣播接收器呢? 只需要新建一個類,讓它繼承自BroadcastReceiver,并重寫父類的onReceive()方法
就行了。這樣當有廣播到來時, onReceive()方法就會得到執行,具體的邏輯就會在這個方法中處理。


我們先通過 動態注冊的方式去編寫一個能夠監聽網絡變化的程序,學習一下廣播接收器的基本用法。
新建項目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;


? ? @Override
? ? 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中定義了一個內部類 NetworkChangeReceiver,這個類是繼承自BroadcastReceiver的,并重寫了
父類的 onReceive()這樣每當網絡狀態發生變化時,onReceive()方法都會得到執行,這里只是簡單的使用Toast提示了一段文本信息
在onCreat()方法,我們首先創建了一個IntenFilter的實例,并給它添加了一個android.net.conn.CONNECTIVITY_CHANGE的
廣播,也就是說當我們想要監聽什么樣的廣播,就在這里添加相應的action。接下來,我們創建一個NetworkChangeReceiver
的實例,然后調用registerReceiver()方法進行注冊,將NetworkChangeReciver的實例和IntentFilter的實例都傳了進去
這樣,NetworkChangeReceiver就會收到所有值為android.conn.CONNECTIVITY_CHANGE的廣播。也就實現了監聽網絡
變化的功能。
最后,動態注冊的廣播接收器一定要取消注冊才行。我們是在onDestroy()方法中通過調用unregisterReceiver()來實現。


總結:
如何創建一個廣播接收器呢?廣播接收器如何接收廣播呢?
1、只需要新建一個類,讓它繼承自BroadcastReceiver,并重寫父類的onReceive()方法
就行了。這樣當有廣播到來時,onReceiver方法就會得到執行,具體的邏輯就會在這個方法中處理。然后創建這個類的
實例,調用其registerReceive()方法進行注冊,最后也可以在onDestroy()方法取消注冊。
2、發送廣播的方法是借助Intent。怎么接收廣播呢?通過創建一個IntentFilter的實例,往里面添加相應的action,
就可以接收對應的廣播。


運行代碼之后,,在注冊完成的時候,會收到一條廣播,然后按下Home鍵,回到主頁面,接著打開Setting程序->
Data usage 進入到數據使用詳情界面,然后嘗試著開關Cellular data 按鈕來啟動和禁用網絡,看到有Toast提醒網絡
發生了變化。
最后可以準確告訴用戶當前是有網絡還是無網絡,我們進一步優化代碼:
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的實例,這是一個系統服務類,專門
用來管理網絡連接的。然后調用它的getAcitiveNetworkInfo()方法得到NetworkInfo的實例,接著調用NetworkInfo的
isAvailable()方法,就可以判斷當前是否有網絡了,最后我們還是通過Toast的方式對用戶進行提示。
Android系統為了保護用戶設備的安全和隱私,做了嚴格的規定,如何程序需要做一些對用戶來說比較敏感的操作,就必須在
配置文件中聲明權限才可以,否則程序將會直接崩潰。打開AndroidManifest.xml文件,在下面加入如下權限就可以訪問
系統網絡狀態了:
<?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有很多操作都是需要聲明權限才可以進行的。
現在我們又可以重新運行程序了。




2、靜態注冊實現開機啟動

動態注冊的廣播接收器可以自由地控制注冊與注銷,有很大的靈活性,但有一個缺點,必須要在程序啟動之后才能接收廣播,因為注冊的邏輯是寫在onCreate()方法中的,可以采取靜態注冊的方式,讓程序在未啟動的情況下接收到廣播;

我們讓程序接收一條開機廣播,當收到這條廣播時就可以在onReceive()方法里執行相應的邏輯,從而實現開機啟動的功能。我們右擊com.example.broadcasttest包,-->New->another-->Broadcast Receiver,將這個廣播接收器命名為BootCompleteReceiver,Exported屬性表示是否允許廣播接收器接收本程序以外的廣播,Enabled屬性表示是否啟用這個廣播接收器。勾選這兩個屬性,點擊Finish完成創建。

然后修改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彈出一段提示信息。

另外靜態的廣播接收器一定要在AndroidManifest.xml文件中注冊才可以使用,不過由于我們使用的是Android Studio的快捷方式創建的廣播接收器,因此注冊這一步已經被自動完成了。代開AndroidManifest.xml文件看一看,代碼如下:

<?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" /><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"></receiver></application></manifest>

可以看到在,<application>標簽內出現了一個新的標簽<receiver>所有靜態的廣播接收器都是在這里進行注冊的。她的用法其實和<activity>標簽非常相似,也是通過android:name來指定注冊具體哪一個廣播接收器,而enabled和exported屬性則是根據我們剛才勾選的狀態自動生成的。

不過目前BootCompleteReceiver還是不能接收到開機廣播的,我們還需要對AndroidManifest.xml文件進行修改才行,如下:

<?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系統啟動完成后會發出一條值為android.intent.action.BOOT_COMPLETED的廣播,因此我們在<intent-filter>標簽里添加了相應的action。另外監聽系統開機廣播也是需要權限的,可以看到,我們使用<uses-permission>標簽又加入了一條android.permission.RECEIVE_BOOT_COMPLETED權限。

我們重新運行程序之后,就可以接收開機廣播了。

我們在廣播接收器中的onReceive()方法都只是簡單的使用Toast提示了一段文本信息,當你真正在項目中使用到它的時候,就可以在里面編寫自己的邏輯。不要在onReceive()方法中添加過多的邏輯或者進行任何的耗時操作,因為在廣播接收器中式不允許開啟線程的,當onReceive()方法運行了較長時間還沒有結束時,程序就會報錯。因此廣播接收器更多的扮演一種打開程序或其他組件的角色,比如創建一條狀態欄通知,或者啟動一個服務等。

















本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274087.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274087.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274087.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

dbus 和 policykit 實例篇(python)

dbus 和 policykit 實例篇&#xff08;python&#xff09; 使用policykit 的程序一般都有一個dbus daemon程序來完成相關操作&#xff0c;這個dbus daemon 會在系統注冊一個system bus 服務名&#xff0c;用于響應要求root privileged的操作&#xff0c;當dbus請求到達時會先驗…

一個實際的sonar代碼檢查的配置文件

國內私募機構九鼎控股打造APP&#xff0c;來就送 20元現金領取地址&#xff1a;http://jdb.jiudingcapital.com/phone.html內部邀請碼&#xff1a;C8E245J &#xff08;不寫邀請碼&#xff0c;沒有現金送&#xff09;國內私募機構九鼎控股打造&#xff0c;九鼎投資是在全國股份…

JavaScript 第二課 JavaScript語法

本章內容&#xff1a;語句變量和數組操作符條件語句和循環語句函數與對象 ------------------------------------------------------------- 準備&#xff1a; 編寫JavaScript腳本只需要一個普通地文本編輯器和一個Web瀏覽器就足啦。 用JavaScript編寫的代碼必須通過HTML/XHTML…

和菜鳥一起學linux之DBUS基礎學習記錄

轉自&#xff1a;http://blog.csdn.net/eastmoon502136/article/details/10044993 D-Bus三層架構 D-Bus是一個為應用程序間通信的消息總線系統, 用于進程之間的通信。它是個3層架構的IPC 系統&#xff0c;包括&#xff1a; 1、函數庫libdbus &#xff0c;用于兩個應用程序互…

Android 第二十課 廣播機制(大喇叭)----發送自定義廣播(包括發送標準廣播和發送有序廣播)

廣播分為兩種類型&#xff1a;標準廣播和有序廣播 我們來看一下具體這兩者的具體區別&#xff1a; 1、發送標準廣播 我們需要先定義一個廣播接收器來準備接收此廣播才行&#xff0c;否則也是白發。 新建一個MyBroadcastReceiver,代碼如下&#xff1a; package com.example.broa…

八大排序算法

概述 排序有內部排序和外部排序&#xff0c;內部排序是數據記錄在內存中進行排序&#xff0c;而外部排序是因排序的數據很大&#xff0c;一次不能容納全部的排序記錄&#xff0c;在排序過程中需要訪問外存。 我們這里說說八大排序就是內部排序。 當n較大&#xff0c;則應采用…

需求?

1 需求怎樣描述清楚&#xff1f; 利用用例技術&#xff0c;一般這里指的是系統用例&#xff1b;包括以下幾個內容&#xff1a; 用例視圖 系統的功能描述&#xff1b; 用例規約 規定了用戶和系統的交互過程&#xff1b;用戶如何使用系統&#xff1b;用戶如何交互&#xff0c;以及…

Android 第二十一課 RecyclerView簡單的應用之編寫“精美”的聊天頁面

1、由于我們會使用到RecyclerView&#xff0c;因此首先需要在app/build.gradle當中添加依賴庫。如下&#xff1a; apply plugin: com.android.application .... dependencies {....compile com.android.support:recyclerview-v7:26.1.0 } 2、然后開始編寫主頁面&#xff0c;修該…

VS 2008 生成操作中各個選項的差別

近日&#xff0c;在編譯C#項目時經常發現有些時候明明代碼沒錯&#xff0c;但就是編譯不過&#xff0c;只有選擇重新編譯或者清理再編譯才會不出錯&#xff0c;本著求學的態度&#xff0c;搜羅了下VS2008IDE中生成操作的種類以及差別&#xff0c;整理如下&#xff1a;內容(Cont…

dbus-python指南

菜鳥學dbus-python&#xff0c;翻譯dbus-python指南&#xff0c;錯誤之處請在所難免&#xff0c;請諸位不吝賜教&#xff0c;多多指正&#xff01;查看英文原版請點這里。 連接總線Connecting to the Bus方法調用Making method calls代理對象proxy objects接口和方法Interfaces…

JavaScript 第三課 DOM

主要內容&#xff1a; 節點5個常用的DOM方法&#xff1a;getElementById、getElementByTagname、getElementByClassName、getAttribute和setAttribute詳細內容: 1、文檔&#xff1a;DOM中的“D”如果沒有document(文檔),DOM也就無從談起。當創建了一個網頁并把它加載到Web瀏覽器…

源碼編譯安裝Nginx

1.源碼下載 Nginx在github上有一個只讀源碼庫&#xff0c;我獲取的源碼方式為&#xff1a; git clone https://github.com/nginx/nginx.git 2.configure 我下載源碼的時候&#xff0c;github上的源碼的目錄結構為: auto, conf, contrib, docs, misc, src共6個目錄。src目錄是…

SOAP協議初級指南(2)

目前的技術存在的問題&#xff1f;   盡管DCOM和IIOP都是固定的協議&#xff0c;業界還沒有完全轉向其中任何一個協議。沒有融合的部分原因是文化的問題所致。而且在當一些組織試圖標準化一個或另一個協議的時候&#xff0c;兩個協議的技術適用性就被提出質疑。傳統上認為DC…

JavaScript 第四課 案例研究:JavaScript圖片庫

主要內容&#xff1a;編寫一個優秀的標記文件編寫一個JavaScript函數以顯示用戶想要查看的內容由標記出發函數調用使用幾個新方法擴展這個JavaScript函數 學習過DOM&#xff0c;我們用JavaScript和DOM去建立一個圖片庫。最好的辦法是什么呢&#xff1f; 利用JavaScript來建立圖…

windows下mongodb安裝與使用整理

一、首先安裝mongodb 1.下載地址&#xff1a;http://www.mongodb.org/downloads 2.解壓縮到自己想要安裝的目錄&#xff0c;比如d:\mongodb 3.創建文件夾d:\mongodb\data\db、d:\mongodb\data\log&#xff0c;分別用來安裝db和日志文件&#xff0c;在log文件夾下創建一個日志文…

可變參數列表(va_list,va_arg,va_copy,va_start,va_end)

本文轉自:http://blog.csdn.net/costa100/article/details/5787068 va_list arg_ptr&#xff1a;定義一個指向個數可變的參數列表指針&#xff1b;      va_start(arg_ptr, argN)&#xff1a;使參數列表指針arg_ptr指向函數參數列表中的第一個可選參數&#xff0c;說明&…

src與href屬性的區別

src和href之間存在區別&#xff0c;能混淆使用。src用于替換當前元素&#xff0c;href用于在當前文檔和引用資源之間確立聯系。 src是source的縮寫&#xff0c;指向外部資源的位置&#xff0c;指向的內容將會嵌入到文檔中當前標簽所在位置&#xff1b;在請求src資源時會將其指向…

USACO4.12Beef McNuggets(背包+數論)

昨天晚上寫的一題 結果USACO一直掛中 今天交了下 有一點點的數論知識 背包很好想 就是不好確定上界 官方題解&#xff1a; 這是一個背包問題。一般使用動態規劃求解。 一種具體的實現是&#xff1a;用一個線性表儲存所有的節點是否可以相加得到的狀態&#xff0c;然后每次可以…

Java 循環語句中 break,continue,return有什么區別?

break 結束循環&#xff0c;跳出循環體,進行后面的程序;continue 結束本次循環&#xff0c;進行下次循環;return 跳出循環體所在的方法&#xff0c;相當于結束該方法; 例子&#xff1a; public class whiletrueTest{public static void main(String[] args) {heihei();haha();…

Epoll模型詳解

轉自http://blog.163.com/huchengsz126/blog/static/73483745201181824629285/ Linux 2.6內核中提高網絡I/O性能的新方法-epoll I/O多路復用技術在比較多的TCP網絡服務器中有使用&#xff0c;即比較多的用到select函數。 1、為什么select落后 首先&#xff0c;在Linux內核中…