CONNECTIVITY_ACTION bash recibido dos veces cuando Wifi conectado

En mi aplicación tengo un BroadcastReceiver que se inicia como un componente a través de una etiqueta , filtrando android.net.conn.CONNECTIVITY_CHANGE intents.

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

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

Funciona bien, pero siempre parece obtener dos bashs idénticos en aproximadamente un segundo cuando se establece una conexión Wifi. Traté de ver cualquier información que pudiera obtener del bash, ConnectivityManager y WifiManager , pero no puedo encontrar nada que distinga las dos intenciones.

Al mirar el registro, hay al menos otro BroadcastReceiver que también recibe los dos bashs idénticos.

Se ejecuta en un HTC Desire con Android 2.2

¿Alguna idea de por qué parece que tengo un bash “duplicado” cuando se conecta Wifi o cuál es la diferencia entre ambos?

Después de una gran cantidad de búsqueda de Google y la depuración, creo que esta es la forma correcta de determinar si WiFi se ha conectado o desconectado.

El método onReceive() en 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 receptor en AndroidManifest.xml

       

Alguna explicación:

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

  • Cuando solo se utiliza WifiManager.NETWORK_STATE_CHANGED_ACTION , no se transmite la intención cuando Wifi se desconecta, sino dos bashs que contienen diferentes instancias de NetworkInfo, lo que permite determinar un evento cuando se conecta Wifi.

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

Saludos, Torsten

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

  • isConnectedOrConnecting()
  • isConnected()

Primera vez isConnectedOrConnecting() devuelve true y isConnected() false
Segunda vez isConnectedOrConnecting() e isConnected() return true

Aclamaciones

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 progtwig.

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

Espero que esto resuelva tu problema.

Se actualizó el código de Torsten, de modo que cuando se desconecta WIFI, solo se actúa sobre la transmisión individual adecuada.

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

Solucioné dos llamadas usando SharedPref con Time.

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

Porque hay un pequeño retraso entre 1.call y 2.call (Alrededor de 200 milisegundos). Entonces en IF con el tiempo, la segunda llamada se detendrá y la primera continuará.

Lo solucioné 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; } } 

Resolví este problema usando el bash adicional para NetworkInfo. En el ejemplo siguiente, el evento onReceive se activa solo una vez si 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 forma en que lo manejé fue simplemente guardando el estado de la red y luego comparándola para ver si había algún 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 el 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.

comprueba networkType from intent y compara 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 sí lo hay. Resulta que getActiveNetworkInfo siempre te devolverá DESCONECTADO / BLOQUEADO en un caso específico cuando la red se cambia mientras el nivel de la batería es bajo y la aplicación simplemente se cambió

Mira esta publicación

Si solo desea recibirlo una vez, simplemente puede controlarlo a través de variables.

  if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { NetworkInfo activeNetwork = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); if (activeNetwork != null) { // connected to the internet if (activeNetwork.isConnected() && !isUpdated) { if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) { // connected to wifi } else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) { // connected to the mobile provider's data plan } isUpdated = true; } else { isUpdated = false; } } } 

Solo escuche la acción “android.net.conn.CONNECTIVITY_CHANGE”. Se transmite cada vez que se establece o destruye la conexión.

“android.net.wifi.STATE_CHANGE” se emitirá cuando se establezca la conexión. Entonces obtienes dos factores desencadenantes.

¡Disfrutar!