1. 程式人生 > >安卓專案實戰之:安卓7.0優化下的全域性網路連線狀態監聽

安卓專案實戰之:安卓7.0優化下的全域性網路連線狀態監聽

須知:Android7.0起網路變化監聽隱式廣播被關閉

在 Android 7.0 版本中除了提供諸多多視窗支援、活動通知、後臺優化、訊息傳遞服務和Vulkan 等新特性和功能外,還對系統和 API 行為做出了各種變更,其中最重要的一點:Android7.0為了進行後臺的優化刪除了三項隱式廣播(網路狀態變更廣播、拍照廣播以及錄影廣播),以幫助優化記憶體使用和電量消耗。 此項變更很有必要,比如說網路變化的廣播(CONNECTIVITY_CHANGE),當網路發生變化時所有註冊了隱式監聽網路變化的app都會被啟動。刪除這些廣播可以顯著提升裝置效能和使用者體驗。同樣地,拍照廣播和錄視訊廣播(ACTION_NEW_PICTURE or ACTION_NEW_VIDEO)也會出現上述情況。

該變更導致在Android N平臺下即使在Manifest.xml清單檔案中註冊了 CONNECTIVITY_ACTION廣播,在網路發生變化時也不會接收到任何的資訊。但是正在前臺執行的應用程式如果在主執行緒中通過Context.registerReceiver()動態註冊了CONNECTIVITY_ACTION廣播,該應用程式仍然可以接收到該廣播。(注:這樣開發者就可以根據不同的網路狀態載入相應的頁面資訊了,從而提高使用者體驗)。

總結:為了避免Android7.0版本接收不到系統網路變化的廣播,強烈建議使用動態註冊廣播的形式來註冊廣播。

1,新增許可權

<!-- 訪問網路.
--> <uses-permission android:name="android.permission.INTERNET" /> <!-- 訪問WiFi狀態. --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 訪問網路狀態, 檢測網路的可用性. --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

2,編寫網路監聽工具類

工具類見本人部落格:安卓專案實戰之:網路連線判斷工具類
直接Copy過來用即可。

3,新建一個介面來接收狀態變化的回撥

public interface INetEvent {
    void onNetChange(int netWorkState);
}

4,新建一個BroadcastReceiver,監聽網路狀態變化

public class NetStateReceiver extends BroadcastReceiver {

    private INetEvent mINetEvent= BaseActivity.mINetEvent;
    @Override
    public void onReceive(Context context, Intent intent) {
        // 如果相等的話就說明網路狀態發生了變化
        if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
            //容錯機制
            if(mINetEvent!=null) {
                // 介面回撥傳過去狀態的型別
                mINetEvent.onNetChange(NetWorkUtils.getNetWorkState(context));
            }
        }
    }
}

5,在清單檔案中配置 (該步驟取消,為適配7.0已在BaseActivity中動態註冊)

<!-- 監聽網路變化的廣播 -->
        <receiver
            android:name=".receiver.NetStateReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
        </receiver>

6,在基類BaseActivity中實現INetEvent介面

public abstract class BaseActivity extends AppCompatActivity implements INetEvent {

    public static INetEvent mINetEvent;
    // 網路狀態變化的廣播接收器
    private NetStateReceiver mNetStateReceiver;
    // 當前網路連線狀態,網路狀態發生變化,該值會動態更新
    // -1:沒有網路    0:行動網路     1:wifi網路
    protect int netWorkState;
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //初始化網路狀態的監聽
        mINetEvent=this; 
        // 初始化時檢查網路連線
        checkNet();
        // 動態註冊網路狀態監聽廣播
        mNetStateReceiver = new NetStateReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(mNetStateReceiver , filter);
    }

    /**
     * 初始化時獲取當前網路狀態
     */
    public void checkNet() {
        this.netWorkState= NetWorkUtils.getNetWorkState(BaseActivity.this);
    }
    
    /**
     * 全域性檢測網路廣播的回撥 處理網路變化
     * @param netWorkState 網路狀態    -1:沒網路  0:行動網路  1:WiFi網路
     */
    public abstract void onNetChanged(int netWorkState);
    
    @Override
    public void onNetChange(int netWorkState) {
        this.netWorkState= netWorkState;
        onNetChanged(netWorkState);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 取消註冊
        unregisterReceiver(mNetStateReceiver);
    }
}

7,具體Activity的實現

public class NetStateActivity extends BaseActivity {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_netstate);
    }

    @Override
    public void onNetChanged(int netWorkState) {
        switch (netWorkState) {
            case  NetWorkUtils.NETWORK_NONE:
                //沒有網路
                break;
            case  NetWorkUtils.NETWORK_MOBILE:
                //行動網路
                break;
            case  NetWorkUtils.NETWORK_WIFI:
                //WiFi網路
                break;
        }
    }
}

廣播監聽只有在網路狀態發生變化的情況下才會觸發回撥,因此當第一次在沒網時啟動app的時候,該監聽並不會回撥,所以我們需要在第一次啟動app時做手動的判斷,上面的處理中我們每次在Activity介面初始化的時候進行了網路判斷,並且將獲取到的網路值傳給了成員變數netWorkState,所以我們可以直接獲取該值進行網路狀態判斷:

// netWorkState就是繼承的父類的成員變數
Toast.makeText(this, "當前網路狀態:"+netWorkState, Toast.LENGTH_SHORT).show();