studio direct android android-wifi android-broadcastreceiver

wifi direct android studio



La intención de CONECTIVIDAD_ACCIÓN se recibió dos veces cuando se conectó Wifi (13)

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

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

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

Funciona bien, pero siempre parece que tengo dos intentos idénticos en aproximadamente un segundo cuando se establece una conexión Wifi. Intenté ver cualquier información que pudiera obtener de la intención, ConnectivityManager y WifiManager , pero no puedo encontrar nada que distinga los dos intentos.

Mirando el registro, hay al menos otro BroadcastReceiver que también recibe los dos intentos idénticos.

Se está ejecutando en un HTC Desire con Android 2.2

¿Alguna idea de por qué parece que tengo una intención "duplicada" cuando se conecta Wifi o cuál es la diferencia entre las dos?


Al encender WIFI,

  1. Con los datos MÓVIL ENCENDIDOS, se envían dos transmisiones: Difusión n. ° 1: datos MÓVILES desconectados y Emisión n. ° 2: WIFI conectado
  2. Con los datos MÓVIL APAGADOS, solo se envía una transmisión: Transmisión n. ° 1: WIFI conectado

Se puede observar un comportamiento similar al apagar el WIFI en las dos condiciones anteriores.

Para distinguir entre los dos, siga # 2 y # 3 a continuación:

@Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "*** Action: " + intent.getParcelableExtra("networkInfo")); NetworkInfo netInfo = intent.getParcelableExtra("networkInfo"); if(intent.getAction().equalsIgnoreCase("android.net.conn.CONNECTIVITY_CHANGE")) { ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo(); if (activeNetInfo != null) { if (netInfo.getType() == ConnectivityManager.TYPE_WIFI) { if (netInfo.getState().name().contains("DISCONNECTED") && activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) { Log.d(TAG, "WIFI disconnect created this broadcast. MOBILE data ON."); // #1 } else if (netInfo.getState().name().contains("CONNECTED") && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) { Log.d(TAG, "WIFI connect created this broadcast."); // #2 } } else if (netInfo.getType() == ConnectivityManager.TYPE_MOBILE) { if (netInfo.getState().name().contains("DISCONNECTED") && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) { Log.d(TAG, "MOBILE data disconnect created this broadcast. WIFI ON."); // #3 } else if (netInfo.getState().name().contains("CONNECTED") && activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) { Log.d(TAG, "MOBILE data connect created this broadcast."); // #4 } } } else { Log.d(TAG, "No network available"); } } }


Después de muchas búsquedas en Google y 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

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

Alguna explicación:

  • Cuando solo estoy considerando ConnectivityManager.CONNECTIVITY_ACTION , siempre tengo dos intentos 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 ninguna intención cuando se desconecta Wifi, sino dos intentos que contienen diferentes instancias de NetworkInfo, lo que permite determinar un evento cuando Wifi está conectado.

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

Saludos, Torsten


Encontré un caso especial para la conectividad de la red que dice que no hay internet pero en realidad la hay Resulta que getActiveNetworkInfo siempre te devolverá DESCONECTADO / BLOQUEADO en un caso específico cuando se cambia la red mientras el nivel de batería es bajo y la aplicación se acaba de cambiar.

Echa un vistazo a esta publicación


La forma en que lo manejé fue simplemente guardando el estado de la red y luego comparándolo 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 onResume de su fragmento o actividad, para que contenga el valor actual:

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

Hice eso en mi BaseFragment , un padre de todos los fragmentos en mi aplicación.


Resolví dos veces la llamada 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 (aproximadamente 200 milisegundos). Así que en IF con el tiempo, la segunda llamada se detendrá y la primera continuará.


Resolví este problema usando la intención extra para NetworkInfo. En el siguiente ejemplo, el evento onReceive se dispara 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; }


Resolví si con dentro

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


Se actualizó el código de Torsten, de modo que cuando WIFI se desconecta, solo se actúa sobre la única emisión apropiada.

Se utilizó 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 estás escuchando en WifiManager.NETWORK_STATE_CHANGED_ACTION , recibirás esto dos veces porque hay 2 métodos en NetworkInfo

  • isConnectedOrConnecting()
  • isConnected()

La primera vez que isConnectedOrConnecting() devuelve true y isConnected() false
La segunda vez que isConnectedOrConnecting() y isConnected() devuelven true

Aclamaciones


Si registró la actividad como un escucha intencional, recibirá el mismo mensaje dos veces. Específicamente, debe elegir si desea escuchar en el nivel del paquete (XML) o en el nivel programático.

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

Espero que esto resuelva tu problema.


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 escucha la acción "android.net.conn.CONNECTIVITY_CHANGE". Se emite cada vez que se establece o se destruye la conexión.

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

¡Disfrutar!


verifique el tipo de red desde 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 } }