1. 程式人生 > >Android中wifi與資料流量的切換監聽

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"/>

以上程式碼很詳細的描述了網路切換的實時檢測,更加詳細豐富的就不在這裡寫出來了。