廣播機制

本文來自郭霖大神的《第一行代碼》。
鄙人不才,抄作筆記,以供回顧,刪改之處,還望見諒。
廣播接收器(Broadcast Receiver)

Android最近廣播分爲兩種類型:標準廣播和有序廣播.

標準廣播 (Normal broadcasts) 是一種完全異步執行的廣播,在廣播發出之後,所有的廣播接收器都會在同一時刻接收到這條廣播信息,因此它們之間沒有任何先後順序.這種廣播效率比較高,同時它也是無法截斷的.

這裏寫圖片描述

有序廣播(Ordered broadcasts)則是一種同步執行的廣播,在廣播發出之後,同一時刻只會有一個廣播接收器能接收到這條廣播消息,當這個廣播接收器中的邏輯執行完畢後,廣播纔會繼續傳遞.所以此時的廣播接收器是有先後順序的,優先級高的廣播接收器就可以先收到廣播消息,並且前面的廣播接收器還可以截斷正在傳遞的廣播,這要後面的廣播接收器就無法收到廣播接收器消息.

這裏寫圖片描述

廣播接收器可以自由地對自己感興趣的廣播進行註冊,這樣當有相應的廣播發出時,廣播接收器就能收到該廣播,並在內部處理相應的邏輯.
註冊廣播的方式一般有兩種,在代碼中註冊和在AndroidManifest.xml中註冊,前者也被稱爲動態註冊,後者也被稱爲靜態註冊.

創建廣播接收器,讓它繼承自BroadcastReceiver,並重寫父類的onReceive()方法就行了.當有廣播到來時,onReceive()方法就會執行.

使用動態註冊的方式編寫一個能夠監控網絡變化的程序,藉此學習一下廣播接收器的基本用法.

新建BroadcastTest項目,修改MainActivity中的代碼:

package com.example.luokexi.broadcasttestdemo2;

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 intentFilter;//意圖過濾器 IntentFilter對象負責過濾掉組件無法響應和處理的Intent
    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        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.makeText(context,"network changes",Toast.LENGTH_SHORT).show();
        }
    }

在MainActivity中定義一個內部類NetworkChangeReceiver,繼承自BroadcastReceiver,並重寫父類的onReceive()方法.當網絡狀態發生變化的時候,onReceive()方法就會得到執行,這裏使用Toast提示了一段文本信息.
onCreate()方法,首先我們創建了一個IntentFilter的實例,並給它添加了一個值爲android.net.conn.CONNECTIVITY_CHANGE的action.爲什麼要添加這個值呢,因爲當網絡狀態發生變化時,系統發出的正是一條爲android.net.conn.CONNECTIVITY _ CHANGE的廣播,也就是說我們的廣播接收器要監聽什麼廣播.就在這裏添加相應的action.接下來創建一個NetworkChangeReceiver的實例,然後調用registerReceiver()方法進行註冊,將NetworkChangeReceiver的實例和IntentFilter的實例都傳了進去,這樣NetworkChange-Receiver就會收到所有值爲android.net.conn.CONNECTIVITY _CHANGE的廣播,也就實現了監聽網絡變化的功能.
最後記得,動態註冊的廣播接收器一定要取消註冊才行,這裏我們是在onDestory()中通過調用unregisterReceiver()方法來實現的. 運行程序,查看效果.首先註冊完成的時候回收到一條廣播,然後按HOME鍵回到主界面(注意不能按Back鍵,會執行onDestroy()方法),接着打開Setting->進入Data usage進入到數據使用詳情界面,然後嘗試開關Cellular data按鈕來啓動和禁用網絡,你就會看到Toast提醒你網絡發生了變化.

下面修改代碼準確的告訴用戶當前是有網絡還是沒有網絡.

public class MainActivity extends AppCompatActivity{
...
}
class NetworkChangeReceiver extends BroadcastReceiver {
 @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.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()方法中,首先通過getSystemService()方法得到了ConnectivityManager的實例,這是一個系統服務類,專門用於管理網絡連接的.然後調用它的getActiveNetwork-Info()方法可以得到NetworkInfo()方法就可以得到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.luokexi.broadcasttestdemo2">
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <application
        android: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>
    </application>

</manifest>

運行效果:
這裏寫圖片描述
這裏寫圖片描述
在Android6.0中還引入了更加嚴格的運行時權限。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章