web-dev-qa-db-fra.com

Comment gérer le changement de réseau entre le wifi et les données mobiles?

Je construis une application VoIP. Pendant un appel VoIP lorsque l'utilisateur bascule entre Wi-Fi et données mobiles, j'ai un problème à gérer le scénario.

Dans mon activité d’écran d’appel, je me suis inscrit pour le récepteur, ce qui m’aide à recevoir des informations sur les scénarios de changement de réseau.

C’est le code que j’utilise pour détecter les changements de réseaux dans la méthode onRecieve.

conn_name est une variable de niveau de classe privée contenant le nom de la connexion précédente.

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



Donc, en utilisant la méthode ci-dessus, je suis capable de détecter les changements de réseau. Mais une chose particulière se produit lorsque je suis connecté au WiFi.
Lorsque mon application démarre initialement, elle est connectée aux données mobiles. Lorsque l'utilisateur entre dans sa zone WiFi connue, il se connecte à son réseau WiFi connu. Comme le Wi-Fi est toujours choisi comme itinéraire par défaut, Android passe au Wi-Fi et je reçois la notification réseau l'informant que le Wi-Fi a été activé.Par conséquent, je mets à jour l'adresse IP de mes applications en adresse IP WiFi.Aucun problème ici. dans le même temps, mais getActiveNetworkInfo () me dit que je suis clairement connecté au WiFi même si j'étais connecté tôt aux données mobiles.

Le problème survient lorsque l'utilisateur éteint le bouton WiFi et que les données mobiles sont toujours connectées mais que je reçois toujours la notification de désactivation du Wi-Fi . Cela m'indique que le réseau est déconnecté même lorsque mon téléphone est toujours connecté à données mobiles . Mais après une seconde je reçois une notification que les données mobiles sont connectées . Mais une fois que je reçois le réseau déconnecté, j'ai fermé mon appel VoIP . Donc, quand je reçois une notification pour WiFi commuté comment puis-je m'assurer que les données mobiles sont toujours connectées . J'ai essayé getActiveNetworkInfo (), mais il est nul lorsque je reçois une notification pour le WiFi désactivé.Alors aidez-moi à résoudre ce problème.

J'ai suivi ces liens.
Appel de l'API Android pour déterminer le paramètre utilisateur "Données activées"
Comment savoir si les "données de réseau mobile" sont activées ou non (même si elles sont connectées par WiFi)?
En utilisant le lien ci-dessus, je suis en mesure de détecter que le bouton de données mobiles a été activé lorsque l'utilisateur s'est connecté à mobiledata.it, ce qui est vrai. Mais le problème se produit lorsque ce cas particulier se produit.
"Maintenant, lorsque le wifi est désactivé, je reçois une notification, mais cela indique que les données mobiles sont désactivées, même lorsque mes données mobiles sont activées. Je ne suis pas en mesure de gérer cette situation car je déconnecte mes appels lorsque je reçois ma notification déconnectée"

16
Jeeva

Vous pouvez utiliser les API de ConnectivityManager : particulièrement dans votre cas d'utilisation vous êtes intéressé par 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);
        }
    }

Mon appareil se connecte à LTE en environ une demi-seconde.

 enter image description here

Cela signifie que vous ne pouvez pas savoir à l'avance si l'appareil se connectera éventuellement à LTE ou s'il ne le fera pas à ce moment-là, lorsque le WIFI sera déconnecté. Ainsi, vous pouvez adopter l'approche suivante: poster une action sur un gestionnaire pour qu'elle se produise dans une seconde et, dans cette action, annuler l'appel. Si la connexion apparaît bientôt - annulez l'action déjà postée. Si vous vous retrouvez dans un code Runnable, la connexion n’est pas établie rapidement, ce qui signifie que vous devez mettre fin à l’appel.


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

L'inconvénient de cette approche est que registerDefaultNetworkCallback() est disponible à partir de l'API 24. Il n'existe pas d'alternative dans ConnectivityManagerCompat non plus. Au lieu de cela, vous pouvez utiliser registerNetworkCallback() qui est disponible à partir de l’API 21.

9
azizbekian

Vous pouvez utiliser BroadcastReceiver et enregistrer NETWORK_STATE_CHANGED_ACTION & WIFI_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();
}

Mise à jour N'oubliez pas de désenregistrer le destinataire BroadcastReceiver onDestroy

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

La réponse que vous recherchez est une BroadcastReceiver. Vérifiez le lien ci-dessous.

BroadcastReceiver lorsque l'état du réseau wifi ou 3G est modifié

J'espère que cela vous aidera à résoudre votre problème et, le cas échéant, envisagez de clore votre question.

0
jyubin patel