web-dev-qa-db-fra.com

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 également 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.), le problème est donc comment puis-je savoir quand c'est vraiment connecté? J'ai des routines que je veux faire quand le wifi est connecté, et je ne veux pas qu'on les appelle trois fois de suite. 

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

Mettre à jour: 

On dirait que c'est 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 éléments chinois sans nom). Sur DHD et sur un téléphone aléatoire connecté en wifi, j'ai reçu 3 messages, sur les téléphones restants, je n'ai reçu qu'un seul message. WTF.

32
Sver

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

En supposant que vous receviez le message de déconnexion lorsque le wifi est déconnecté, je suppose que le premier est le bon et que les 2 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 pouvant basculer entre connexion et déconnexion et appeler 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;
        }
    }
}
54
brianestey

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

Lorsque le type de connexion est modifié, cela fonctionnera évidemment. Lorsque le périphérique sort de la connexion, activeNetworkInfo sera nul et currentType sera NO_CONNECTION_TYPE comme dans le cas 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
Aleksandar Ilic

Dans mon cas, j'enregistrais mes BroadcastReceivers dans onResume et ne les annulais que dans onDestroy.

Cela a entraîné l'enregistrement de chaque destinataire de la radiodiffusion 3 ou 4 fois, en fonction du nombre de reprises de l'activité.

Régler votre récepteur radio au bon endroit en termes de cycle de vie d'activité vous permettra de ne plus recevoir d'appels confus.

3
Simon

Enregistrez votre destinataire LocalBroadcastreceiver dans oncreate() même et non dans onResume(). non enregistré dans onDestroy

1
Sreenivasulu Y

Ce qui me préoccupe avec l'approche proposée par Aleksander, c'est qu'elle ne prend pas en compte les modifications de réseau du même type, par exemple. d'un réseau WiFi à un autre.

Je propose de comparer extraInfo du réseau actif, qui contient le nom du réseau, par exemple. 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
dutchman711

J'ai une application qui télécharge des données lorsque l'utilisateur revient en ligne. Étant donné que mon récepteur de radiodiffusion 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
John