CONNECTIVITY_ACTION intención recibida dos veces cuando Wifi conectado

En mi aplicación tengo un BroadcastReceiver que se lanza como un componente a través de una etiqueta <receiver> , filtrado android.net.conn.CONNECTIVITY_CHANGE intents.

Mi objetivo es simplemente saber cuándo se estableció una conexión Wifi, así que lo que estoy haciendo en onReceive() es:

 NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.isConnected()) { // Wifi is connected } 

Funciona muy bien, pero siempre parecen tener dos intentos idénticos dentro de un segundo cuando se establece una conexión Wifi. Intenté ver cualquier información que pudiera obtener de la intención, el ConnectivityManager y WifiManager , pero no puedo encontrar nada que distingue las dos intenciones.

Mirando el registro, hay al menos otro BroadcastReceiver que también recibe las dos intenciones idénticas.

Se está ejecutando en un HTC Desire con Android 2.2

¿Alguna idea de por qué me parece obtener una intención "duplicada" cuando Wifi conecta o lo que la diferencia entre los dos podría ser?

Después de un montón de google y depuración, creo que esta es la forma correcta de determinar si Wifi ha conectado o desconectado.

El método onReceive() en el BroadcastReceiver:

 public void onReceive(final Context context, final Intent intent) { if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); if(networkInfo.isConnected()) { // Wifi is connected Log.d("Inetify", "Wifi is connected: " + String.valueOf(networkInfo)); } } else if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI && ! networkInfo.isConnected()) { // Wifi is disconnected Log.d("Inetify", "Wifi is disconnected: " + String.valueOf(networkInfo)); } } } 

Junto con el siguiente elemento del receptor en AndroidManifest.xml

 <receiver android:name="ConnectivityActionReceiver" android:enabled="true" android:label="ConnectivityActionReceiver"> <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> <action android:name="android.net.wifi.STATE_CHANGE"/> </intent-filter> </receiver> 

Algunas explicaciones:

  • Cuando considero sólo ConnectivityManager.CONNECTIVITY_ACTION , siempre obtengo dos intentos que contienen idénticas instancias de NetworkInfo (tanto getType () == TYPE_WIFI como isConnected () == true) cuando Wifi conecta el problema descrito en esta pregunta.

  • Cuando sólo se utiliza WifiManager.NETWORK_STATE_CHANGED_ACTION , no hay intención de difusión cuando Wifi se desconecta, pero dos intentos que contienen diferentes instancias de NetworkInfo, lo que permite determinar un evento cuando Wifi está conectado.

NOTA: He recibido un solo informe de intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO) NPE) donde el intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO) devolvió null. Por lo tanto, incluso si parece ser extremadamente raro que ocurra, podría ser una buena idea agregar un cheque nulo.

Saludos, Torsten

Si está escuchando WifiManager.NETWORK_STATE_CHANGED_ACTION , recibirá esto dos veces porque hay 2 métodos en el NetworkInfo

  • isConnectedOrConnecting()
  • isConnected()

Primera vez isConnectedOrConnecting() devuelve true y isConnected() false
Segunda vez isConnectedOrConnecting() y isConnected() devuelven true

Aclamaciones

Actualizado el código de Torsten, de tal manera que cuando WIFI se desconecta, sólo la única difusión adecuada se actúa sobre.

Utilizado NetworkInfo.getDetailedState () == DetailedState.DISCONNECTED para la comprobación.

 public void onReceive(final Context context, final Intent intent) { if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { NetworkInfo networkInfo = intent .getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); if (networkInfo.isConnected()) { // Wifi is connected Log.d("Inetify","Wifi is connected: " + String.valueOf(networkInfo)); } } else if (intent.getAction().equals( ConnectivityManager.CONNECTIVITY_ACTION)) { NetworkInfo networkInfo = intent .getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); if (networkInfo.getDetailedState() == DetailedState.DISCONNECTED) { // Wifi is disconnected Log.d("Inetify","Wifi is disconnected: "+String.valueOf(networkInfo)); } } } 

Si registró la actividad como un oyente intencionado, recibirá el mismo mensaje dos veces. Específicamente, debe elegir si desea escuchar en el nivel de paquete (XML) o en el nivel de programación.

Si configura una clase para un receptor de difusión y adjunta la escucha Y agrega un filtro de intención a la actividad, el mensaje se replicará dos veces.

Espero que esto solucione su problema.

He resuelto dos veces la llamada usando SharedPref con tiempo.

 private static final Long SYNCTIME = 800L; private static final String LASTTIMESYNC = "DATE"; SharedPreferences sharedPreferences; private static final String TAG = "Connection"; @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "Network connectivity change"); sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); final ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); final NetworkInfo ni = connectivityManager.getActiveNetworkInfo(); if (ni != null && ni.isConnected()) { if(System.currentTimeMillis()-sharedPreferences.getLong(LASTTIMESYNC, 0)>=SYNCTIME) { sharedPreferences.edit().putLong(LASTTIMESYNC, System.currentTimeMillis()).commit(); // Your code Here. } } else if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE)) { Log.d(TAG, "There's no network connectivity"); } } 

Debido a que hay un pequeño retardo entre 1. llamadas y 2. llamadas (aproximadamente 200 milisegundos). Así que en SI con el tiempo, la segunda llamada se detendrá y la primera continuará.

Resuelvo si con

 onCreate() intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); intentFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED"); intentFilter.addAction("android.net.wifi.STATE_CHANGE"); ctx.registerReceiver(outgoingReceiver, intentFilter); 

en

 BroadcastReceiver public void onReceive(Context context, Intent intent) { if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.isConnected()) { // Wifi is connected Log.d("Inetify", "Wifi is connected: " + String.valueOf(networkInfo)); Log.e("intent action", intent.getAction()); if (isNetworkConnected(context)){ Log.e("WiFi", "is Connected. Saving..."); try { saveFilesToServer("/" + ctx.getString(R.string.app_name).replaceAll(" ", "_") + "/Temp.txt"); } catch (IOException e) { e.printStackTrace(); } } } }} boolean isNetworkConnected(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo ni = cm.getActiveNetworkInfo(); if (ni != null) { Log.e("NetworkInfo", "!=null"); try{ //For 3G check boolean is3g = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) .isConnectedOrConnecting(); //For WiFi Check boolean isWifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI) .isConnected(); Log.e("isWifi", "isWifi="+isWifi); Log.e("is3g", "is3g="+is3g); if (!isWifi) { return false; } else { return true; } }catch (Exception er){ return false; } } else{ Log.e("NetworkInfo", "==null"); return false; } } 

Solucioné este problema utilizando el intento extra para NetworkInfo. En el ejemplo siguiente, el evento onReceive se activa sólo una vez si el wifi está conectado o es móvil.

 if (intent.getAction().equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION)) { NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); boolean screenIsOn = false; // Prüfen ob Screen on ist PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { screenIsOn = pm.isInteractive(); } else { screenIsOn = pm.isScreenOn(); } if (Helper.isNetworkConnected(context)) { if (networkInfo.isConnected() && networkInfo.isAvailable()) { Log.v(logTAG + "onReceive", "connected"); if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { Log.v(logTAG + "onReceive", "mobile connected"); } else if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { Log.v(logTAG + "onReceive", "wifi connected"); } } } 

Y mi ayudante:

  public static boolean isNetworkConnected(Context ctx) { ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo ni = cm.getActiveNetworkInfo(); return ni != null; } 

La manera en que lo manejé, fue simplemente guardando el estado de la red y luego comparándola para ver si había un cambio .

 public class ConnectivityChangedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { boolean previouslyConnected = MyApp.getInstance().isNetworkPreviouslyConnected(); boolean currentlyConnected = MyApp.getInstance().isNetworkConnected(); if (previouslyConnected != currentlyConnected) { // do something and reset MyApp.getInstance().resetNetworkPreviouslyConnected(); } } } 

Si este es el enfoque que adopta, es importante restablecerlo en onResume de su fragmento o actividad, de modo que contenga el valor actual:

 @Override public void onResume() { super.onResume(); MyApp.getInstance().resetNetworkPreviouslyConnected(); } 

Lo hice en mi BaseFragment , un padre de todos los fragmentos en mi aplicación.

Compruebe networkType de la intención y compare activeNetworkInfo.getType ()

  Bundle bundle = intent.getExtras(); ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo ni = manager.getActiveNetworkInfo(); if(ni != null && ni.getState() == NetworkInfo.State.CONNECTED) { if(bundle.getInt("networkType") == ni.getType()) { // active network intent } } 

Encontró un caso especial para la conectividad de red diciendo que no hay Internet, pero en realidad no es. Resulta que getActiveNetworkInfo siempre te devuelve DESCONECTADO / BLOQUEADO en un caso específico cuando se cambia la red mientras el nivel de la batería es bajo y la aplicación acaba de ser cambiada

Echa un vistazo a este post

Sólo escucha la acción "android.net.conn.CONNECTIVITY_CHANGE". Se transmite cuando se establece o se destruye la conexión.

"Android.net.wifi.STATE_CHANGE" se transmitirá cuando se establezca la conexión. Así que obtienes dos disparadores.

¡Disfrutar!

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.