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

Jee*_*eva 19 networking android android-wifi mobile-data android-connectivitymanager

我正在建立一个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;          
        }        
    }
Run Code Online (Sandbox Code Playgroud)



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

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

我已经关注了这个链接.
Android API调用以确定用户设置"已启用数据"
如何启用或禁用"移动网络数据"(即使通过WiFi连接)?
使用上面的链接我能够检测到当用户与mobiledata连接时已经启用了移动数据按钮.这给了我真实的信息.但是当这种特殊情况发生时就会出现问题.
"现在,当wifi被禁用时,我会收到通知,但它显示即使我的移动数据已启用也会禁用移动数据.我无法处理这种情况,因为我在收到断开连接的通知时断开了我的呼叫"

azi*_*ian 24

您可以使用以下API ConnectivityManager:特别是在您感兴趣的用例中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.

在此输入图像描述

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


    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两者中都没有替代方案.相反,您可以使用registerNetworkCallback()API 21中提供的内容.

  • 使用registerDefaultNetworkCallback,您事先不会知道。或者,您可以注册两个单独的回调,一个用于 TRANSPORT_WIFI,另一个用于 TRANSPORT_CELLULAR。这样您就可以参考这两个网络(如果可用)。大多数 OEM 总是在后台保持 Cell 网络处于活动状态。如果没有,您可以使用 CM#requestNetwork *请求*蜂窝网络。 (2认同)