Question BroadcastReceiver reçoit plusieurs messages identiques pour un événement


J'ai enregistré un récepteur qui écoute les événements du réseau:

<receiver 
    android:label="NetworkConnection"
    android:name=".ConnectionChangeReceiver" >
    <intent-filter >
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

le récepteur est aussi très simple:

public class ConnectionChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
        if (activeNetInfo != null) {
                Log.v("@@@","Receiver : " + activeNetInfo);
        } else {
            Log.v("@@@","Receiver : " + "No network");
        }
    }
}

Le problème est que lorsque le Wifi est connecté, je reçois 3 messages identiques à la suite, comme ceci:

Receiver : NetworkInfo: type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true
Receiver : NetworkInfo: type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true
Receiver : NetworkInfo: type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true

Ils sont tous "CONNECTED / CONNECTED" (ne devraient-ils pas être quelque chose comme CONNECTING / OBTAINING_IPADDR, etc.), alors le problème est de savoir comment savoir quand il est vraiment connecté? J'ai quelques routines que je veux faire quand le wifi est réellement connecté, et je ne veux pas qu'ils soient appelés trois fois de suite.

PS: 3G n'envoie qu'un seul message, donc pas de problème ici.

Mettre à jour:

Cela semble être un problème spécifique à l'appareil.

Pour le test j'ai pris 2 Desire HD, et 4 téléphones Android aléatoires (différents modèles Aquos et des trucs chinois sans nom). Sur les deux DHD et un téléphone aléatoire sur la connexion wifi, j'ai reçu 3 messages, sur les téléphones restants, je n'ai reçu qu'un seul message. WTF.


32
2017-12-07 09:06


origine


Réponses:


Recevoir plusieurs émissions est un problème spécifique à l'appareil. Certains téléphones envoient une émission alors que d'autres envoient 2 ou 3. Mais il y a un travail autour de:

En supposant que vous obtenez le message de déconnexion lorsque le wifi est déconnecté, je suppose que le premier est le bon et les deux autres ne sont que des échos pour une raison quelconque.

Pour savoir que le message a été appelé, vous pouvez avoir un booléen statique qui est basculé entre la connexion et la déconnexion et qui appelle uniquement vos sous-routines lorsque vous recevez une connexion et que le booléen est vrai. Quelque chose comme:

public class ConnectionChangeReceiver extends BroadcastReceiver {
    private static boolean firstConnect = true;

    @Override
    public void onReceive(Context context, Intent intent) {
        final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
        if (activeNetInfo != null) {
            if(firstConnect) { 
                // do subroutines here
                firstConnect = false;
            }
        }
        else {
            firstConnect= true;
        }
    }
}

52
2017-12-07 10:05



Vous pouvez également mettre en cache dans un champ statique le dernier type de connexion traité et vérifier les diffusions entrantes. De cette façon, vous ne recevrez qu'une seule diffusion par type de connexion.

Lorsque le type de connexion est modifié, cela fonctionne évidemment. Lorsque l'appareil est hors connexion activeNetworkInfo sera nul et currentType sera NO_CONNECTION_TYPE comme par défaut

public class ConnectivityReceiver extends BroadcastReceiver {

    /** The absence of a connection type. */
    private static final int NO_CONNECTION_TYPE = -1;

    /** The last processed network type. */
    private static int sLastType = NO_CONNECTION_TYPE;

    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager connectivityManager = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        final int currentType = activeNetworkInfo != null
                ? activeNetworkInfo.getType() : NO_CONNECTION_TYPE;

        // Avoid handling multiple broadcasts for the same connection type
        if (sLastType != currentType) {
            if (activeNetworkInfo != null) {
                boolean isConnectedOrConnecting = activeNetworkInfo.isConnectedOrConnecting();
                boolean isWiFi = ConnectivityManager.TYPE_WIFI == currentType;
                boolean isMobile = ConnectivityManager.TYPE_MOBILE == currentType;

                // TODO Connected. Do your stuff!
            } else {
                // TODO Disconnected. Do your stuff!
            }

            sLastType = currentType;
        }
}

8
2018-03-16 15:12



Dans mon cas, je inscrivais mes BroadcastReceivers dans onResume et seulement en les désinscrivant dans onDestroy.

Cela a provoqué l'enregistrement de chaque poste de radio 3 ou 4 fois, en fonction du nombre de reprises de l'activité.

Le fait de configurer votre émetteur-récepteur au bon endroit en termes de cycle de vie d'activité vous permettra de ne plus recevoir d'appels confus.


2
2018-03-19 10:16



Enregistrez votre LocalBroadcastreceiver dans oncreate() lui-même pas en onResume(). non enregistré dans onDestroy


1
2017-12-22 13:15



J'ai une application qui télécharge des données lorsque l'utilisateur revient en ligne. Étant donné que mon récepteur de diffusion peut recevoir l’intention plusieurs fois, les données peuvent être téléchargées plusieurs fois. Pour gérer cela, j'utilise un service qui ne fera rien s'il est déjà en cours d'exécution.

Récepteur de diffusion:

public class ConnectionChangeReceiver extends BroadcastReceiver {
    private static boolean firstConnect = true;

    @Override
    public void onReceive(Context context, Intent intent) {
        final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
        if (activeNetInfo != null) {
            startService();
        }   
    }
}

Un service:

public class MyService extends Service {
    private boolean mRunning;

    @Override
    public void onCreate() {
        super.onCreate();
        mRunning = false;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (!mRunning) {
            mRunning = true;
            uploadTheData();
        }
        return super.onStartCommand(intent, flags, startId);
    }
}

0
2017-08-06 18:54



Ce qui m'inquiète avec l'approche proposée par Aleksander, c'est qu'il ne considère pas les modifications de réseau du même type, par ex. d'un réseau WiFi à un autre.

Je propose de comparer le extraInfo du réseau actif, qui contient le nom du réseau, par ex. WiFi SSID ou nom de réseau mobile comme VZW

 String currentNetworkName = "";

 ConnectivityManager connectivityManager =
            ((ConnectivityManager) context.getSystemService(
                    Context.CONNECTIVITY_SERVICE));

    NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
    boolean connected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    if (connected) {
        // prevent duplicate connect broadcasts
        String extraInfo = activeNetwork.getExtraInfo();
        if(! currentNetworkName.equals(extraInfo)) {
            // to do: handle network changes
            currentNetworkName = extraInfo;
        }
    } else {
        Log.d(TAG, "is not connected");
        isConnected = false;
        currentNetworkName = "";
    }

0
2017-08-07 14:18