BroadcastReceiver odbiera wiele identycznych wiadomości dla jednego zdarzenia

Zarejestrowałem odbiornik, który nasłuchuje zdarzeń sieciowych:

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

Odbiornik jest również bardzo prosty:

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

Problem polega na tym, że po podłączeniu Wifi otrzymuję 3 identyczne wiadomości pod rząd, jak to:

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

Wszystkie są "CONNECTED/CONNECTED" (nie powinny być czymś w rodzaju CONNECTING/OBTAINING_IPADDR, itp.), więc problem polega na tym, jak rozpoznać, że jest naprawdę podłączony? Mam kilka procedur, które chcę zrobić, gdy wifi jest rzeczywiście podłączony, i nie chcę będą wywoływane trzy razy z rzędu.

PS: 3G wysyła tylko jedną wiadomość, więc nie ma problemu.

Aktualizacja:

Wygląda na to, że to problem specyficzny dla urządzenia.

Do testu wziąłem 2 Desire HD i 4 losowe telefony z Androidem(różne modele Aquos i trochę chińskich rzeczy bez nazwy). Na obu DHD i jeden losowy telefon na wifi connect dostałem 3 wiadomości, na pozostałych telefonach dostałem tylko jedną wiadomość. WTF.

Author: Sver, 2011-12-07

6 answers

Odbieranie wielu transmisji jest problemem specyficznym dla urządzenia. Niektóre telefony wysyłają tylko jedną transmisję, podczas gdy inne wysyłają 2 lub 3. Ale jest praca wokół:

Zakładając, że otrzymasz komunikat o odłączeniu, Gdy wifi jest odłączony, domyślam się, że pierwszy jest prawidłowy, a pozostałe 2 są tylko echem z jakiegoś powodu.

Aby wiedzieć, że wiadomość została wywołana, możesz mieć statyczny boolean, który zostanie przełączony między connect i disconnect i tylko wywoła Twój podprogramy, gdy otrzymasz połączenie i wartość logiczna jest true. Coś w stylu:

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
Author: brianestey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-13 10:03:37

Możesz również buforować w polu statycznym ostatni Obsługiwany typ połączenia i sprawdzić przed nadchodzącymi transmisjami. W ten sposób otrzymasz tylko jedną transmisję na każdy typ połączenia.

Gdy typ połączenia zostanie zmieniony, będzie to oczywiście działać. Gdy urządzenie zostanie wyłączone z połączenia, activeNetworkInfo będzie równe null, a currentType będzie równe NO_CONNECTION_TYPE jak w przypadku domyślnym.

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
Author: Aleksandar Ilic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-16 15:32:06

W moim przypadku rejestrowałem swoje Broadcastreceivery w onResume i tylko je wyrejestrowywałem w onDestroy.

To spowodowało, że każdy broadcastreceiver został zarejestrowany 3 lub 4 razy, w zależności od tego, ile razy aktywność zostanie wznowiona.

Ustawienie broadcastreceiver we właściwym miejscu pod względem cyklu życia aktywności pozwoli Ci przestać uzyskiwać wiele mylących połączeń.

 2
Author: Simon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-19 10:16:42

Zarejestruj swój LocalBroadcastreceiver w oncreate() nie w onResume(). Niezarejestrowana Strona onDestroy

 1
Author: Sreenivasulu Y,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-22 14:11:30

Mam aplikację, która przesyła dane, gdy użytkownik wróci online. Ponieważ mój odbiornik może odbierać intencję wiele razy, może to prowadzić do przesłania danych więcej niż raz. Aby sobie z tym poradzić, korzystam z usługi, która nic nie zrobi, jeśli jest już uruchomiona.

Odbiornik Transmisji:

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

Usługa:

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
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-06 18:54:21

Moje zaniepokojenie podejściem zaproponowanym przez Aleksandra polega na tym, że nie uwzględnia on zmian sieci tego samego typu, np. z jednej sieci WiFi na drugą.

Proponuję porównać extraInfo aktywnej sieci, która zawiera nazwę sieci, np. WiFi SSID lub nazwę sieci komórkowej jak 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
Author: dutchman711,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-07 14:18:23