首页 文章

如何处理wifi和移动数据之间的网络变化?

提问于
浏览
17

我正在 Build 一个VoIP应用程序 . 当用户在WiFi与移动数据之间切换时,在VoIP呼叫期间,我在处理场景时遇到问题 .

在我的通话屏幕活动中,我已注册接收器,这有助于我获得有关网络更改方案的通知 .

这是我用于检测onRecieve方法中网络变化的代码 .

conn_name 是包含先前连接名称的私有类级别变量 .

ConnectivityManager connectivity_mgr = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
    NetworkInfo net_info = connectivity_mgr.getActiveNetworkInfo();

    if (net_info != null && net_info.isConnectedOrConnecting() && !conn_name.equalsIgnoreCase("")) {
        new_con = net_info.getExtraInfo();        
        if (new_con != null && !new_con.equalsIgnoreCase(conn_name))
            network_changed = true;
        conn_name = (new_con == null) ? "" : new_con;
        connectionStatus ="connected";        
    } else {
        if (net_info != null && conn_name.equalsIgnoreCase("")){
            conn_name = net_info.getExtraInfo();
            connectionStatus ="connected";
            network_changed = true;
        }else if(!new_con.equals(conn_name)) {    
            conn_name = "";
            connectionStatus ="disconnected";
            network_changed = true;          
        }        
    }

所以使用上面的方法我能够检测网络变化 . 但是当我与WiFi连接时会发生一件奇怪的事情 .
当我的应用程序最初启动时,它与移动数据连接 . 当用户进入他已知的WiFi区域时,他连接到他已知的WiFi . 由于WiFi总是被选为默认路由,因此android会切换到WiFi,我会收到WiFi已经打开的网络通知 . 所以我将我的应用IP地址更新为WiFi IP地址 . 这里没有问题 . 但是移动数据仍然是连接的同时但 getActiveNetworkInfo() 告诉我即使我早期连接到移动数据,我也能清楚地连接WiFi .

所以问题是当用户关闭WiFi按钮,移动数据仍然连接但我仍然收到WiFi关闭通知 . 它表明即使我的手机仍然连接到移动数据,网络仍然断开连接 . 但是一秒钟后我收到移动数据连接的通知 . 但是一旦我收到网络断开连接,我就关闭了我的VoIP电话 . 因此,当我收到关闭WiFi的通知时,我如何确定移动数据是否仍然连接 . 我尝试了getActiveNetworkInfo()但是当我收到关闭WiFi的通知时它恰好是null . 所以请帮我解决这个特殊问题 .

我已经关注了这个链接 .
Android API call to determine user setting "Data Enabled"
How to tell if 'Mobile Network Data' is enabled or disabled (even when connected by WiFi)?
使用上面的链接我能够检测到当用户与mobiledata连接时已经启用了移动数据按钮 . 这给了我真实的信息 . 但是当这种特殊情况发生时就会出现问题 .
"Now when wifi is disabled i get notification but it shows that mobile data is disabled even when my mobile data is enabled.I am not able to handle this situation as i disconnect my calls when i receive my disconnected notification"

3 回答

  • 0

    你正在寻找的答案是 BroadcastReceiver . 检查以下链接 .

    BroadcastReceiver when wifi or 3g network state changed

    希望它能帮助您解决问题,如果是,请考虑结束您的问题 .

  • 11

    您可以使用ConnectivityManager的API:特别是在您感兴趣的registerDefaultNetworkCallback()用例中:

    public class TestActivity extends AppCompatActivity {
    
            private ConnectivityManager manager;
            private final ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
                @Override
                public void onAvailable(Network network) {
                    super.onAvailable(network);
                    // this ternary operation is not quite true, because non-metered doesn't yet mean, that it's wifi
                    // nevertheless, for simplicity let's assume that's true
                    Log.i("vvv", "connected to " + (manager.isActiveNetworkMetered() ? "LTE" : "WIFI"));
                }
    
                @Override
                public void onLost(Network network) {
                    super.onLost(network);
                    Log.i("vvv", "losing active connection");
                }
            };
    
            @Override
            protected void onCreate(@Nullable Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
    
                manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
                manager.registerDefaultNetworkCallback(networkCallback);
            }
    
            @Override
            protected void onDestroy() {
                super.onDestroy();
                manager.unregisterNetworkCallback(networkCallback);
            }
        }
    

    我的设备在大约半秒内连接到LTE .

    enter image description here

    这意味着,当WIFI断开连接时,您无法事先知道设备最终是否会连接到LTE或者没有连接到LTE . 因此,您可以采用以下方法:在一秒钟内对处理程序发布操作,并在此操作中取消调用 . 如果很快就会出现连接 - 取消预先安排以前发布的操作 . 如果您最终处于 Runnable 代码中,则表示连接未快速 Build ,这意味着您应该结束通话 .

    public class TestActivity extends AppCompatActivity {
    
            private ConnectivityManager manager;
    
            private final Handler handler = new Handler();
            private final ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
                @Override
                public void onAvailable(Network network) {
                    super.onAvailable(network);
                    Log.i("vvv", "connected to " + (manager.isActiveNetworkMetered() ? "LTE" : "WIFI"));
    
                    // we've got a connection, remove callbacks (if we have posted any)
                    handler.removeCallbacks(endCall);
                }
    
                @Override
                public void onLost(Network network) {
                    super.onLost(network);
                    Log.i("vvv", "losing active connection");
    
                    // Schedule an event to take place in a second
                    handler.postDelayed(endCall, 1000);
                }
            };
    
            private final Runnable endCall = new Runnable() {
                @Override
                public void run() {
                    // if execution has reached here - feel free to cancel the call
                    // because no connection was established in a second
                }
            };
    
            @Override
            protected void onCreate(@Nullable Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
    
                manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
                manager.registerDefaultNetworkCallback(networkCallback);
            }
    
            @Override
            protected void onDestroy() {
                super.onDestroy();
                manager.unregisterNetworkCallback(networkCallback);
                handler.removeCallbacks(endCall);
            }
        }
    

    该方法的缺点是,registerDefaultNetworkCallback()从API 24开始可用 . 在ConnectivityManagerCompat中也没有替代方案 . 相反,您可以使用API 21中提供的registerNetworkCallback() .

  • 2

    您可以使用 BroadcastReceiver 并注册 NETWORK_STATE_CHANGED_ACTIONWIFI_STATE_CHANGED_ACTION .

    private boolean isConnected;
    
    final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent == null || intent.getAction() == null)
                return;
            switch (intent.getAction()){
                case WifiManager.NETWORK_STATE_CHANGED_ACTION :
                case WifiManager.WIFI_STATE_CHANGED_ACTION :
                    if (!isConnected && isOnline(BaseActivity.this)) {
                        isConnected = true;
                        // do stuff when connected
                        Log.i("Network status: ","Connected");
                    }else{
                        isConnected = isOnline(BaseActivity.this);
                        Log.i("Network status: ","Disconnected");
                    }
                    break;
            }
        }
    };
    
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        isConnected = isOnline(this);
        final IntentFilter filters = new IntentFilter();
        filters.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        filters.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        registerReceiver(broadcastReceiver, filters);
    }
    
    
    public static boolean isOnline(Context ctx) {
        ConnectivityManager cm = (ConnectivityManager) ctx
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo netInfo = cm != null
                ? cm.getActiveNetworkInfo()
                : null;
        return netInfo != null && netInfo.isConnectedOrConnecting();
    }
    

    Update 别忘了取消注册收件人 BroadcastReceiver onDestroy

    @Override
    protected void onDestroy() {
        unregisterReceiver(broadcastReceiver);
        super.onDestroy();
    }
    

相关问题