從0系統學Android–5.1 廣播機制

  • 2020 年 3 月 11 日
  • 筆記

本系列持續更新中…. 初級階段內容參考《第一行程式碼》

第五章:全局大喇叭—詳解廣播機制

5.1 廣播機制簡介

Android 中每個應用程式都可以對自己感興趣的廣播進行註冊,這樣當註冊的廣播發出時,應用程式就會接受到。這些廣播可能來自系統,也可能來自其他應用程式。

接受廣播需要用到Broadcast Receiver 廣播接收器。

Android 中的廣播分為兩種:標準廣播和有序廣播

標準廣播:是一種完全非同步執行的廣播,在廣播發出後幾乎所有的接收器都會在同一時刻受到廣播消息。因此它們之間沒有任何的先後順序,這種廣播效率比較高,但同時意味著不能被截斷。

有序廣播:是一種同步執行的廣播,在廣播發出後,同一時刻只有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執行完畢後廣播才會繼續傳播。有序廣播是有先後順序的,優先順序高的會優先接受到廣播並且可以截斷正在傳遞的廣播。

5.2 接受系統廣播

Android 系統內置了許多的系統級別的廣播,我們可以通過這些廣播來獲取手機的一些狀態。比如手機開機會發送一條廣播,電池電量發生變化會發送廣播,時間或者時區發生改變會發送廣播等等。

5.2.1 動態註冊監聽網路變化

註冊廣播的方式有兩種:一種是在程式碼中註冊稱為動態註冊,另一種是在 AndroidManifest.xml 中註冊稱為靜態註冊

如何才能接受到廣播呢?首先要創建一個廣播接收器。

新建一個類,讓他繼承 BoradcastReceiver 並重寫 onReceive() 方法,當接受到廣播後就會執行 onReceive() 方法,這樣一個簡單的廣播包接收器就創建好了。

下面來具體實踐一下:

public class NetChangeActivity extends AppCompatActivity {      NetWorkChangeReceiver netWorkChangeReceiver;      @Override      protected void onCreate(@Nullable Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_ui);          IntentFilter intentFilter = new IntentFilter();   // 每當網路狀態發生改變的時候都會接受到廣播(有網路了,沒有網路了,切換到 WiFi了)        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");          netWorkChangeReceiver = new NetWorkChangeReceiver();          registerReceiver(netWorkChangeReceiver,intentFilter);      }        class NetWorkChangeReceiver extends BroadcastReceiver{            @Override          public void onReceive(Context context, Intent intent) {              Toast.makeText(context,"網路狀態發生變化",Toast.LENGTH_SHORT).show();          }      }        @Override      protected void onDestroy() {          super.onDestroy();          unregisterReceiver(netWorkChangeReceiver);      }  }  

其實具體過程很簡單,步驟:

  1. 新建一個廣播接收器
  2. 通過 IntentFilter 來指定要接受的廣播
  3. registerReceiver() 來註冊廣播
  4. 需要取消註冊

進一步編寫,告訴用戶當前是有網路還是沒有網路

  ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);              NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();              if (networkInfo!=null && networkInfo.isAvailable()){                  Toast.makeText(context,"網路可用",Toast.LENGTH_SHORT).show();              }else {                  Toast.makeText(context,"網路不可用",Toast.LENGTH_SHORT).show();              }  

主要是通過 ConnectivityManager 這個專門用於管理網路的服務類來實現的。

注意這裡需要訪問系統的網路狀態,需要聲明許可權,在 AndroidManifest.xml

   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  

5.2.2 靜態註冊實現開機啟動

動態註冊廣播接受有一個缺點就是必須程式運行了才可以接受到廣播,原因很簡單,只有我們打開了對應的程式頁面運行了註冊的邏輯才可以接受到廣播。

那麼怎麼樣可以讓程式在沒有啟動的情況下就能接受到廣播呢?這就需要靜態註冊了。

靜態註冊可以讓程式沒有啟動就接受到廣播消息

程式碼實現:首先我們新建一個 Java 類繼承自 BroadcastReceiver

public class BootCompleteReceiver extends BroadcastReceiver {      @Override      public void onReceive(Context context, Intent intent) {          Toast.makeText(context,"開機完成",Toast.LENGTH_SHORT).show();      }  }  

很簡單,當接收到開機廣播後就Toast 一下就可以了。下面開始進行靜態註冊,到 AndroidManifest.xml 中,其實和註冊 Activity 非常相似

   <receiver android:name="com.example.firstcode.fifty_chapter.bootreceiver.BootCompleteReceiver"                       android:enabled="true"              android:exported="true">              <intent-filter>                  <action android:name="android.intent.action.BOOT_COMPLETED"/>              </intent-filter>          </receiver>  

重點是 exported 設置為 true 表示可以接受本程式之外的廣播,不然就接受不到程式外的廣播了,因為要接受開機廣播,不是我們的程式自己發出的所以要設置為 true 。enable 的意思就是啟用這個廣播接收器。

通過 action 標籤指定要接受的廣播。接受開機廣播需要許可權

 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>  

好了,這樣在開機的時候就會接受到廣播了。

注意: 廣播接收器 onReceive() 方法裡面不要做太多的邏輯或者任何的耗時操作,因為在廣播接收器中是不允許開啟執行緒的,並且如果 onReceive() 方法運行了較長時間而沒有結束的話程式就會報錯。因此廣播接收器扮演的是一種打開程式其他組件的角色,比如創建狀態欄通知,或者啟動一個服務等等