安卓專案實戰之:安卓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();