Android中wifi與資料流量的切換監聽
最近在做一個wifi和移動資料的監控功能,來來回回折騰了一陣子,這個模組的主要功能是監聽整個APP的wifi與資料流量的切換,讓使用者使用專用流量,而不是用wifi,給一個彈窗,點選確認,自動切換資料流量,關閉wifi。我的思路是寫一個靜態廣播,監聽在廣播裡面進行監聽,啟用系統彈窗,點選確認,自動切換網路,這裡面有一個坑就是彈窗會在廣播中多次被呼叫,其實只調用了一次,但是實際上多次呼叫系統的彈窗會一個疊加一個,搞了好久,終於搞好了,原來是系統廣播導致的疊加,詳情看程式碼:
ConnectivityManager類
ConnectivityManager 是一個網路連線的管理類,裡面封裝了網路請求的詳細資訊,包括WiFi與移動資料流量的開關狀態,正在開啟與關閉的狀態,連線狀態等等,很適合做網路監聽。還有一個類WifiManager ,這個類專門用來做WiFi的監聽,他的監聽效果比ConnectivityManager更加詳細豐富,可以檢測但是對流量沒法生效。這裡使用ConnectivityManager 就足夠了。
一、註冊廣播
寫一個類繼承自BroadcastReceiver。
@Override public void onReceive(Context context, Intent intent) { ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo gprs = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); if (intent.getAction().equals("Android.net.conn.CONNECTIVITY_CHANGE")) { //移動資料連線上時 if (gprs.isConnected()){ } //wifi連線上時 if (wifi.isConnected()) { // 切換網路,關閉wifi,開啟流量 if (isShow) {//做一個標記,避免多次彈窗的疊加bug,初始值為true,重要 switchNetwork(context); } } //斷網時 if (!netManager.getGRPS().isConnected() || !netManager.getGRPS().isConnected()) { } }
二、彈窗
彈窗一般用四種常用的方式:
1、使用popupwindow
2、使用dialog
3、WindowManager
4、系統彈窗
一般的彈窗需要依附於activity,在activity中彈窗,但是在服務中,不能簡單的使用這種方式,一般是採用系統的彈窗,他的優先順序很高,覆蓋於應用介面的最高層,並且要設定setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT),要不然會崩潰的。
private void switchNetwork(final Context context) { AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AlertDialog); builder.setTitle("提示"); builder.setMessage("請關閉wifi,開啟行動網路"); builder.setCancelable(false); builder.setPositiveButton("確定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 控制網路的開關 controlNetWork(context); isShow = true; } }); AlertDialog dialog = builder.create(); // 需要把對話方塊的型別設為TYPE_SYSTEM_ALERT,否則對話方塊無法在廣播接收器裡彈出 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); dialog.show(); isShow = false; }
三、網路切換
wifi的網路切換比較容易,直接設定setWifiEnabled就可以完成切換,而資料流量的切換比較麻煩,他的方法是私有的,無法呼叫,我們可以通過反射,找到他的方法進行呼叫:具體看程式碼
private void controlNetWork(Context context) { WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); // 允許流量,阻止wifi wifiManager.setWifiEnabled(false);//false表示斷開WiFi ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); boolean connected = conn.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isConnected(); if (!connected) { ConnectivityManager gprsCM = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); Class conmanClass; try { conmanClass = Class.forName(gprsCM.getClass().getName()); final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService"); iConnectivityManagerField.setAccessible(true); final Object iConnectivityManager = iConnectivityManagerField.get(gprsCM); final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName()); final Method setMobileDataEnabledMethod = iConnectivityManagerClass .getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE); setMobileDataEnabledMethod.setAccessible(true);//true表示連線網路 setMobileDataEnabledMethod.invoke(iConnectivityManager, true); } catch (Exception e) { e.printStackTrace(); } }
在清單檔案中註冊廣播
<receiver
android:name=".NetChangeReceiver"
android:label="NetChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
新增許可權:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
以上程式碼很詳細的描述了網路切換的實時檢測,更加詳細豐富的就不在這裡寫出來了。