Android中BroadcastReceiver的兩種註冊方式(靜態和動態)詳解

来源:http://www.cnblogs.com/panhouye/archive/2016/12/13/6168156.html
-Advertisement-
Play Games

今天我們一起來探討下安卓中BroadcastReceiver組件以及詳細分析下它的兩種註冊方式。 BroadcastReceiver也就是“廣播接收者”的意思,顧名思義,它就是用來接收來自系統和應用中的廣播。在Android系統中,廣播體現在方方面面,例如當開機完成後系統會產生一條廣播,接收到這條廣 ...


今天我們一起來探討下安卓中BroadcastReceiver組件以及詳細分析下它的兩種註冊方式。

BroadcastReceiver也就是“廣播接收者”的意思,顧名思義,它就是用來接收來自系統和應用中的廣播。在Android系統中,廣播體現在方方面面,例如當開機完成後系統會產生一條廣播,接收到這條廣播就能實現開機啟動服務的功能;當網路狀態改變時系統會產生一條廣播,接收到這條廣播就能及時地做出提示和保存數據等操作;當電池電量改變時,系統會產生一條廣播,接收到這條廣播就能在電量低時告知用戶及時保存進度等等。Android中的廣播機制設計的非常出色,很多事情原本需要開發者親自操作的,現在只需等待廣播告知自己就可以了,大大減少了開發的工作量和開發周期。而作為應用開發者,就需要數練掌握Android系統提供的一個開發利器,那就是BroadcastReceiver。

在我們詳細分析創建BroadcastReceiver的兩種註冊方式前,我們先羅列本次分析的大綱:

(1)對靜態和動態兩種註冊方式進行概念闡述以及演示實現步驟

(2)簡述兩種BroadcastReceiver的類型(為後續註冊方式的對比做準備)

(3)在預設廣播類型下設置優先順序和無優先順序情況下兩種註冊方式的比較

(4)在有序廣播類型下兩種註冊方式的比較

(5)通過接受打電話的廣播,在程式(Activity)運行時和終止運行時,對兩種註冊方式的比較

(6)總結兩種方式的特點

第一步:靜態和動態註冊方式基本概念以及實現步驟

構建Intent,使用sendBroadcast方法發出廣播定義一個廣播接收器,該廣播接收器繼承BroadcastReceiver,並且覆蓋onReceive()方法來響應事件註冊該廣播接收器,我們可以在代碼中註冊(動態註冊),也可以AndroidManifest.xml配置文件中註冊(靜態註冊)。

動態註冊:

效果如下圖:

這裡就不演示點擊按鈕佈局的實現了,MainActivity.java中實現代碼如下:

 1 import android.content.BroadcastReceiver;
 2 import android.content.Context;
 3 import android.content.Intent;
 4 import android.content.IntentFilter;
 5 import android.support.v7.app.AppCompatActivity;
 6 import android.os.Bundle;
 7 import android.view.Gravity;
 8 import android.view.View;
 9 import android.widget.Toast;
10 
11 public class MainActivity extends AppCompatActivity {
12     DynamicReceiver dynamicReceiver;
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         setContentView(R.layout.activity_main);
17         //實例化IntentFilter對象
18         IntentFilter filter = new IntentFilter();
19         filter.addAction("panhouye");
20         dynamicReceiver = new DynamicReceiver();
21         //註冊廣播接收
22         registerReceiver(dynamicReceiver,filter);
23     }
24     //按鈕點擊事件
25     public void send2(View v){
26         Intent intent = new Intent();
27         intent.setAction("panhouye");
28         intent.putExtra("sele","潘侯爺");
29         sendBroadcast(intent);
30     }
31     /*動態註冊需在Acticity生命周期onPause通過
32      *unregisterReceiver()方法移除廣播接收器,
33      * 優化記憶體空間,避免記憶體溢出
34      */
35     @Override
36     protected void onPause() {
37         super.onPause();
38         unregisterReceiver(new MyReceiver());
39     }
40     //通過繼承 BroadcastReceiver建立動態廣播接收器
41     class DynamicReceiver extends BroadcastReceiver{
42         @Override
43         public void onReceive(Context context, Intent intent) {
44             //通過土司驗證接收到廣播
45             Toast t = Toast.makeText(context,"動態廣播:"+ intent.getStringExtra("sele"), Toast.LENGTH_SHORT);
46             t.setGravity(Gravity.TOP,0,0);//方便錄屏,將土司設置在屏幕頂端
47             t.show();
48         }
49     }
50 }

建立方法代碼中做了詳細註釋,有不明白的地方請留言討論。

靜態註冊:

效果如下:

靜態註冊建立第一步,新建BroadcastReceiver,見下圖:

通過以上步驟,生成MyReceiver.java文件:

 1 import android.content.BroadcastReceiver;
 2 import android.content.Context;
 3 import android.content.Intent;
 4 import android.view.Gravity;
 5 import android.widget.Toast;
 6 
 7 public class MyReceiver extends BroadcastReceiver {
 8     public MyReceiver() {
 9     }
10     @Override
11     public void onReceive(Context context, Intent intent) {
12         Toast t = Toast.makeText(context,"靜態廣播:"+intent.getStringExtra("info"), Toast.LENGTH_SHORT);
13         t.setGravity(Gravity.TOP,0,0);
14         t.show();
15     }
16 }

生成MyReceiver.java的同時,修改AndroidMainfest.xml配置文件中的代碼:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3     package="com.example.administrator.day19">
 4 <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
 5     <application
 6         android:allowBackup="true"
 7         android:icon="@mipmap/ic_launcher"
 8         android:label="@string/app_name"
 9         android:supportsRtl="true"
10         android:theme="@style/AppTheme">
11         <activity android:name=".MainActivity">
12             <intent-filter>
13                 <action android:name="android.intent.action.MAIN" />
14 
15                 <category android:name="android.intent.category.LAUNCHER" />
16             </intent-filter>
17         </activity>
18         //生成的receiver配置文件
19         <receiver
20             android:name=".MyReceiver"
21             android:enabled="true"
22             android:exported="true">
23             <intent-filter>
24             //自定義Action
25                 <action android:name="MLY" />
26             </intent-filter>
27         </receiver>
28     </application>
29 </manifest>

最後在MainActivity.java文件中添加按鈕點擊事件,如下:

 1 import android.content.BroadcastReceiver;
 2 import android.content.Context;
 3 import android.content.Intent;
 4 import android.content.IntentFilter;
 5 import android.support.v7.app.AppCompatActivity;
 6 import android.os.Bundle;
 7 import android.view.Gravity;
 8 import android.view.View;
 9 import android.widget.Toast;
10 
11 public class MainActivity extends AppCompatActivity {
12     DynamicReceiver dynamicReceiver;
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         setContentView(R.layout.activity_main);
17     }
18     //靜態廣播點擊
19     public void send(View v){
20         Intent intent = new Intent();
21         intent.setAction("MLY");
22         intent.putExtra("info","panhouye");
23         sendBroadcast(intent);
24     }
25 }


至此,兩種註冊方式的實現代碼演示完畢,歡迎探討。

第二步:為方便後續分析,這裡插入BroadcastReceiver的兩種常用類型

(1Normalbroadcasts:預設廣播

         發送一個預設廣播使用Context.sendBroadcast()方法,普通廣播對於多個接收者來說是完全非同步的,通常每個接收者都無需等待即可以接收到廣播,接收者相互之間不會有影響。對於這種廣播,接收者無法終止廣播,即無法阻止其他接收者的接收動作。

(2)orderedbroadcasts:有序廣播

    發送一個有序廣播使用Context.sendorderedBroadcast()方法,有序廣播比較特殊,它每次只發送到優先順序較高的接收者那裡,然後由優先順序高的接受者再傳播到優先順序低的接收者那裡,優先順序高的接收者有能力終止這個廣播。

發送有序廣播:sendorderedBroadCast()

在註冊廣播中的<intent-filter>中使用android:priority屬性。這個屬性的範圍在-1000到1000,數值越大,優先順序越高。在廣播接收器中使用setResultExtras方法將一個Bundle對象設置為結果集對象,傳遞到下一個接收者那裡,這樣優先順序低的接收者可以用getResuttExtras獲取到最新的經過處理的信息集合。使用sendorderedBroadcast方法發送有序廣播時,需要一個許可權參數,如果為null則表示不要求接收者聲明指定的許可權,如果不為null則表示接收者若要接收此廣播,需聲明指定許可權。這樣做是從安全形度考慮的,例如系統的簡訊就是有序廣播的形式,一個應用可能是具有攔截垃圾簡訊的功能,當簡訊到來時它可以先接受到簡訊廣播,必要時終止廣播傳遞,這樣的軟體就必須聲明接收簡訊的許可權。

第三步:在預設廣播下兩種註冊方式的比較

(1)兩種註冊方式均不設置優先順序

這裡將動態與靜態兩種註冊的廣播觸發集中在一個按鈕上,顯示效果如下(未設置優先順序的情況下,先動態後靜態):

這裡同樣不演示按鈕佈局文件,以及靜態註冊涉及AndroidMainfest.xml和MyReceiver.java文件。直接展示MainActicity.java的實現代碼:

 1 import android.content.BroadcastReceiver;
 2 import android.content.Context;
 3 import android.content.Intent;
 4 import android.content.IntentFilter;
 5 import android.support.v7.app.AppCompatActivity;
 6 import android.os.Bundle;
 7 import android.view.Gravity;
 8 import android.view.View;
 9 import android.widget.Toast;
10 
11 public class MainActivity extends AppCompatActivity {
12     DynamicReceiver dynamicReceiver;
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         setContentView(R.layout.activity_main);
17         IntentFilter filter = new IntentFilter();
18         filter.addAction("panhouye");
19         dynamicReceiver = new DynamicReceiver();
20         registerReceiver(dynamicReceiver,filter);
21     }
22     //靜態廣播點擊
23     public void send(View v){
24         Intent intent = new Intent();
25         //設置與動態相同的Action,方便同時觸發靜態與動態
26         intent.setAction("panhouye");
27         intent.putExtra("info","潘侯爺");
28         sendBroadcast(intent);//預設廣播
29     }
30     @Override
31     protected void onPause() {
32         super.onPause();
33         unregisterReceiver(new MyReceiver());
34     }
35     class DynamicReceiver extends BroadcastReceiver{
36         @Override
37         public void onReceive(Context context, Intent intent) {
38             Toast t = Toast.makeText(context,"動態廣播:"+ intent.getStringExtra("info"), Toast.LENGTH_SHORT);
39             t.setGravity(Gravity.TOP,0,0);
40             t.show();
41         }
42     }
43 }

(2)將動態優先順序設置為最低-1000,靜態優先順序設置為最高1000

顯示效果如下(動態仍先於靜態被接收到):

MainActivity中動態優先順序設置如下:

1 protected void onCreate(Bundle savedInstanceState) {
2         super.onCreate(savedInstanceState);
3         setContentView(R.layout.activity_main);
4         IntentFilter filter = new IntentFilter();
5         filter.addAction("panhouye");
6         filter.setPriority(-1000);//設置動態優先順序
7         dynamicReceiver = new DynamicReceiver();
8         registerReceiver(dynamicReceiver,filter);
9     }

AndroidMainfest.xml中靜態優先順序設置如下:

1 <receiver
2     android:name=".MyReceiver"
3     android:enabled="true"
4     android:exported="true">
5     //設置靜態優先順序
6     <intent-filter android:priority="1000">
7           <action android:name="panhouye" />
8     </intent-filter>
9 </receiver>

第四步:在有序廣播下兩種註冊方式比較

靜態廣播1(優先順序為200),靜態廣播2(優先順序為300),靜態廣播3(優先順序為400),靜態廣播優先順序為(-100),動態廣播優先順序為0。顯示效果如下:

出現順序由優先順序決定,由高到低分別為靜態3-靜態2-靜態1-動-靜態。(這裡參照前文代碼)

第五步:接受打電話的廣播,比較程式運行中與結束運行時,兩種註冊方式的比較

本次比較採用比對Log的方式對兩種註冊方式進行比較,在MainActivity.java中會插入Activity全部生命周期用於檢測Log分析。

AndroidMainfest.xml配置文件代碼如下:

 1 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 2     package="com.example.administrator.test19">
 3     //添加撥打電話許可權
 4 <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
 5     <application
 6         android:allowBackup="true"
 7         android:icon="@mipmap/ic_launcher"
 8         android:label="@string/app_name"
 9         android:supportsRtl="true"
10         android:theme="@style/AppTheme">
11         <activity android:name=".MainActivity">
12             <intent-filter>
13                 <action android:name="android.intent.action.MAIN" />
14 
15                 <category android:name="android.intent.category.LAUNCHER" />
16             </intent-filter>
17         </activity>
18         <receiver
19             android:name=".StaticReceiver"
20             android:enabled="true"
21             android:exported="true">
22             <intent-filter>
23                 //設置打電話對應的action
24                 <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
25             </intent-filter>
26         </receiver>
27     </application>
28 </manifest>

MainActivity.java中實現代碼(動態註冊將解除註冊放在onDestory方法內是因為在真機測試過程中撥打電話,需要返回主頁面,而此操作會造成Activity處於onStop狀態,若放在onPause中,將無法在程式運行時啟用動態註冊接受廣播。真實環境下建議在onpause下解除註冊,儘早釋放記憶體,避免記憶體溢出):

 1 import android.content.BroadcastReceiver;
 2 import android.content.Context;
 3 import android.content.Intent;
 4 import android.content.IntentFilter;
 5 import android.support.v7.app.AppCompatActivity;
 6 import android.os.Bundle;
 7 import android.util.Log;
 8 
 9 public class MainActivity extends AppCompatActivity {
10     DynamicReceiver dynamicReceiver;//聲明動態註冊廣播接收
11     @Override
12     protected void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.activity_main);
15         IntentFilter filter = new IntentFilter();
16         filter.addAction("android.intent.action.NEW_OUTGOING_CALL");
17         dynamicReceiver = new DynamicReceiver();
18         registerReceiver(dynamicReceiver,filter);
19         Log.i("Tag","Activity-onCreate");
20     }
21     @Override
22     protected void onStart() {
23         super.onStart();
24         Log.i("Tag","Activity-onStart");
25     }
26     @Override
27     protected void onResume() {
28         super.onResume();
29         Log.i("Tag","Activity-onResume");
30     }
31     @Override
32     protected void onPause() {
33         super.onPause();
34         Log.i("Tag","Activity-onPause");
35     }
36     @Override
37     protected void onStop() {
38         super.onPause();
39         Log.i("Tag","Activity-onStop");
40     }
41     @Override
42     protected void onDestroy() {
43         super.onDestroy();
44         Log.i("Tag","Activity-onDestroy");
45         unregisterReceiver(dynamicReceiver);
46     }
47     class DynamicReceiver extends BroadcastReceiver{
48         @Override
49         public void onReceive(Context context, Intent intent) {
50             Log.i("Tag","動態註冊廣播接收到您正在撥打電話"+getResultData());
51         }
52     }
53 }

StaticReceiver.java中實現代碼:

 1 import android.content.BroadcastReceiver;
 2 import android.content.Context;
 3 import android.content.Intent;
 4 import android.util.Log;
 5 public class StaticReceiver extends BroadcastReceiver {
 6     public StaticReceiver() {
 7     }
 8     @Override
 9     public void onReceive(Context context, Intent intent) {
10         Log.i("Tag","靜態註冊廣播接收到您正在撥打電話"+getResultData());
11     }
12 }

(1)在未退出Activity時,撥打電話,Log如下:

由Log可知在未退出Activity是,兩種方式均可接受到廣播。

(2)在退出Activity時,撥打電話,Log如下(即便不解除註冊,動態仍無法接受到廣播):

在退出程式(Activity)時,只有靜態註冊方式可以接受到廣播。

第六步:總結兩種註冊方式特點

廣播接收器註冊一共有兩種形式:靜態註冊和動態註冊.

兩者及其接收廣播的區別:

1)動態註冊廣播不是常駐型廣播,也就是說廣播跟隨Activity的生命周期。註意在Activity結束前,移除廣播接收器。

靜態註冊是常駐型,也就是說當應用程式關閉後,如果有信息廣播來,程式也會被系統調用自動運行。

2)當廣播為有序廣播時:優先順序高的先接收(不分靜態和動態)。同優先順序的廣播接收器,動態優先於靜態

3)同優先順序的同類廣播接收器,靜態:先掃描的優先於後掃描的,動態:先註冊的優先於後註冊的。

4)當廣播為預設廣播時:無視優先順序,動態廣播接收器優先於靜態廣播接收器。同優先順序的同類廣播接收器,靜態:先掃描的優先於後掃描的,動態:先註冊的優先於後冊的。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • React.js入門筆記 核心提示 這是本人學習react.js的第一篇入門筆記,估計也會是該系列涵蓋內容最多的筆記,主要內容來自英文官方文檔的快速上手部分和阮一峰博客教程。當然,還有我自己嘗試的實例。日後還將對官方文檔進階和高級部分分專題進行學習並記錄。 儘管前端學習面臨著各種各樣的焦慮,儘管越來 ...
  • 移動端不能使用click,因為click會有300ms。所有有了fastclick這樣的解決方案。然後fastclick並沒有解決點擊態(用戶點擊的瞬間要有及時的外觀變化反饋)的問題。hover會有不消失的問題,所有大家一般用:active。利用 :active 偽類來設置某元素被點擊時的點擊態樣式 ...
  • 第一個場景第一級:對象的多態性 第二個場景:第一級,需要有什麼類型就要去判斷if else 去判斷,要是有需要添加一個地圖,又需要改密碼了 第二級:這樣不管你有多少個類型,都不需要改主代碼 ...
  • 瀏覽器在讀取HTML文件的時候,只有當遇到<script>標簽的時候,才會喚醒所謂的“JavaScript解析器”開始工作。 JavaScript解析器工作步驟: 1、“找一些東西”: var、 function、 參數;(也被稱之為預解析) 備註:如果遇到重名分為以下兩種情況: 遇到變數和函數重名 ...
  • 在我們製作網頁時,例如導航等,會遇到很多的一些小圖標,這裡以京東的小三角(如下圖) 舉例,來介紹常用的一些方法。 方法一:也是比較簡單的一種方法。用background 來做,一般用一個行內標簽如 i ,s 等 先轉換 顯示方式 display:block;,然後設置寬高。 如果不是單一的圖片,而是 ...
  • Base64是網路上最常見的用於傳輸8Bit位元組代碼的編碼方式之一,在瞭解Base64編碼之前,先瞭解幾個基本概念:位、位元組。 位:"位(bit)"是電腦中最小的數據單位。每一位的狀態只能是0或1; 位元組:8個二進位位構成1個"位元組(Byte)",位元組是存儲空間的基本計量單位。1個位元組可以儲存1個 ...
  • <!DOCTYPE html><html> <head> <meta charset="utf-8"> <title></title> <style type="text/css"> *{ margin: 0; padding: 0; } .box{ width: 180px; height: 30 ...
  • Array.prototype.reduce() 概述 reduce()方法是數組的一個實例方法(共有方法),可以被數組的實例對象調用。reduce() 方法接收一個函數作為累加器(accumulator),數組中的每個值(從左到右)開始縮減,最終為一個值。 語法 arr.reduce(callba ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...