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

rggaifut  于 2022-11-27  发布在  Android
关注(0)|答案(4)|浏览(189)

我正在构建一个网络电话应用程序。在网络电话通话过程中,当用户在WiFi和移动的数据之间切换时,我在处理该场景时遇到了问题。
在我的呼叫屏幕活动中,我已经注册了接收器,这有助于我获得有关网络更改情况的通知。
这是我在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关闭的通知时,它恰好为空。
我已经关注了这个链接:
Android API调用以确定用户设置“数据已启用”
如何判断“移动的网络数据”是启用还是禁用(即使通过WiFi连接)?
使用上面的链接,我可以检测到移动的数据按钮已启用时,用户已连接到mobiledata.it给我真的。但问题发生时,这种特殊情况发生。
现在,当wifi被禁用时,我会收到通知,但它显示移动的数据被禁用,即使我的移动数据被启用。我无法处理这种情况,因为我在收到断开连接通知时断开了电话。

ncecgwcz

ncecgwcz1#

您可以利用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。

这意味着,您无法事先知道,当WIFI断开时,设备最终是否会连接到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开始可用。

toe95027

toe950272#

我的RxJava实现

class ConnectivityMonitor : ConnectivityManager.NetworkCallback() {
    var networkTimeout: Disposable? = null

    override fun onAvailable(network: Network?) {
        super.onAvailable(network)
        Timber.d("Network available")
        networkTimeout?.dispose()
    }

    override fun onLosing(network: Network?, maxMsToLive: Int) {
        super.onLosing(network, maxMsToLive)
        Timber.d("onLosing")
    }

    override fun onLost(network: Network?) {
        super.onLost(network)
        Timber.d("onLost")

        networkTimeout = Single.timer(5, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe { _ -> Timber.d("Network lost") }
    }

    override fun onUnavailable() {
        super.onUnavailable()
        Timber.d("Network unavailable")
    }
}

监听程序设置:

private fun setupListeners() {
        // connection listener
        val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            connectivityManager.registerDefaultNetworkCallback(connectivityMonitor)
        } else {
            val builder = NetworkRequest.Builder()
            connectivityManager.registerNetworkCallback(builder.build(), connectivityMonitor)
        }
    }

计时器/一次性用品的使用允许切换连接类型之间的延迟。

daolsyd0

daolsyd03#

您可以使用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();
}

更新不要忘记注销接收器BroadcastReceiver销毁时

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

w1jd8yoj4#

感谢您的贡献@azizbiken,我已经在compose中的ProducerScope中实现了同样的事情

fun networkCallback(producer: ProducerScope<ConnectionState>, context: Context, callback: (ConnectionState) -> Unit): ConnectivityManager.NetworkCallback {
return object : ConnectivityManager.NetworkCallback() {
    var unAvailableJob: Job? = null
    override fun onAvailable(network: Network) {
        //cancel the coroutine once you get network instead of updating no network status
        unAvailableJob?.cancel()
            callback(ConnectionState.Available)
    }

    override fun onLost(network: Network) {
        unAvailableJob = producer.launch {
            delay(1000)
            callback(ConnectionState.Unavailable)
        }
    }
}
}

这是调用代码

val callback = networkCallback(this,context = applicationContext, callback = { connectionState -> trySend(connectionState) })

相关问题