it-swarm.com.de

Wie gehe ich mit dem Netzwerkwechsel zwischen WLAN und mobilen Daten um?

Ich baue eine VoIP-App. Während eines VoIP-Anrufs, wenn der Benutzer zwischen WLAN und mobilen Daten wechselt, habe ich ein Problem mit dem Szenario.

In meiner Anrufbildschirmaktivität habe ich mich für den Empfänger registriert, wodurch ich über die Netzwerkänderungsszenarien informiert werden kann.

Dies ist der Code, den ich für das Erkennen von Änderungen in Netzwerken in der onRecieve-Methode verwende.

conn_name ist eine Variable auf Klassenebene, die den vorherigen Verbindungsnamen enthält.

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;          
        }        
    }



Mit der obigen Methode kann ich Netzwerkänderungen erkennen. Aber eine besondere Sache passiert, wenn ich mit WiFi verbunden bin.
Wenn meine App zum ersten Mal mit mobilen Daten verbunden ist. Wenn der Benutzer seinen bekannten WLAN-Bereich betritt, wird er mit seinem bekannten WLAN verbunden. Da WiFi immer als Standardroute ausgewählt ist, wechselt Android zu WiFi und ich erhalte die Netzwerkbenachrichtigung, dass WiFi aktiviert wurde. Daher aktualisiere ich meine IP-Adresse der Apps auf WiFi-IP-Adresse. Es sind also keine Probleme hier. Aber es sind noch immer mobile Daten verbunden gleichzeitig aber getActiveNetworkInfo () sagt mir, dass ich mit WiFi eindeutig verbunden bin, auch wenn ich früher mit mobilen Daten verbunden war.

Das Problem ist also, wenn der Benutzer die WLAN-Taste ausschaltet und die mobilen Daten immer noch verbunden sind, aber ich erhalte immer noch die Benachrichtigung, dass das WLAN deaktiviert ist. Es zeigt mir an, dass das Netzwerk getrennt ist, auch wenn mein Telefon noch verbunden ist mobile data . Aber nach einer Sekunde erhalte ich eine Benachrichtigung, dass mobile Daten verbunden sind . Aber sobald ich das Netzwerk getrennt habe, habe ich meinen VoIP-Anruf geschlossen ..__ Wenn ich eine Benachrichtigung für WiFi erhalte, wird die Verbindung hergestellt Wie kann ich sichergehen, ob mobile Daten noch angeschlossen sind ... Ich habe es mit getActiveNetworkInfo () versucht, aber es ist null, wenn ich eine Benachrichtigung für WLAN erhalte. So helfen Sie mir bitte, dieses spezielle Problem zu lösen.

Ich bin diesen Links gefolgt.
Android-API-Aufruf zum Ermitteln der Benutzereinstellung "Data Enabled"
Wie kann ich feststellen, ob "Mobile Network Data" aktiviert oder deaktiviert ist (auch wenn eine WLAN-Verbindung besteht)?
Mithilfe des obigen Links kann ich feststellen, dass die Schaltfläche für mobile Daten aktiviert wurde, wenn der Benutzer sich mit mobiledata.it verbunden hat, was mir stimmt. Das Problem tritt jedoch auf, wenn dieser spezielle Fall eintritt.
"Jetzt, wenn WLAN deaktiviert ist, erhalte ich eine Benachrichtigung, aber es zeigt an, dass mobile Daten deaktiviert sind, selbst wenn meine mobilen Daten aktiviert sind. Ich bin nicht in der Lage, diese Situation zu handhaben.

16
Jeeva

Sie können die APIs von ConnectivityManager verwenden: Insbesondere in Ihrem Anwendungsfall interessieren Sie sich für 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);
        }
    }

Mein Gerät stellt in etwa einer halben Sekunde eine Verbindung zu LTE her.

enter image description here

Das bedeutet, dass Sie nicht vorher wissen können, ob sich das Gerät zu einem Zeitpunkt mit LTE verbindet oder nicht, wenn die WLAN-Verbindung getrennt wird. Sie können also folgende Vorgehensweise wählen: Sie können eine Aktion für einen Handler buchen, die in einer Sekunde ausgeführt wird, und innerhalb dieser Aktion den Anruf abbrechen. Wenn die Verbindung zu einem beliebigen Zeitpunkt angezeigt wird, wird die zuvor geplante Aktion nicht mehr geplant. Wenn Sie im Runnable-Code landen, wurde die Verbindung nicht schnell hergestellt, was bedeutet, dass Sie den Anruf beenden sollten.


    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);
        }
    }

Der Nachteil des Ansatzes ist, dass registerDefaultNetworkCallback() ab API 24 verfügbar ist. In ConnectivityManagerCompat gibt es keine Alternative. Sie können stattdessen registerNetworkCallback() verwenden, das in API 21 verfügbar ist.

9
azizbekian

Sie können BroadcastReceiver verwenden und NETWORK_STATE_CHANGED_ACTION & WIFI_STATE_CHANGED_ACTION registrieren.

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 Vergessen Sie nicht die Registrierung des Empfängers BroadcastReceiver onDestroy

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

Meine Implementierung mit 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")
    }
}

Listener-Setup:

    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)
        }
    }

Die Verwendung des Timers/Disposable ermöglicht Verzögerungen zwischen dem Umschalten der Verbindungstypen.

1
William Reed

Die Antwort, die Sie suchen, ist eine BroadcastReceiver. Überprüfen Sie den Link unten.

BroadcastReceiver bei Änderung des WLAN- oder 3G-Netzwerkstatus

Ich hoffe, es hilft Ihnen bei der Lösung Ihres Problems. Falls ja, ziehen Sie in Betracht, Ihre Frage zu schließen.

0
jyubin patel