CONNECTIVITY_ACTION received twice when connecting Wi-Fi

In my application, I have a BroadcastReceiver that runs as a component via the <receiver> , filtering android.net.conn.CONNECTIVITY_CHANGE intentions.

My goal is simply to know when the Wi-Fi connection was established, so what I do in onReceive() :

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

It works fine, but I always get two identical intentions for about one second when a Wi-Fi connection is established. I tried to look at any information that I could get from intent, ConnectivityManager and WifiManager , but I can not find anything that distinguishes two intentions.

Having looked at the magazine, there is at least one more BroadcastReceiver , which also receives two identical intentions.

It works on HTC Desire with Android 2.2

Any idea why I seem to get a “duplicate” intent when Wifi connects or what's the difference between the two?

+49
android android-broadcastreceiver android-wifi
Mar 11 '11 at 17:11
source share
14 answers

NOTE. For the latest up-to-date answer, see this answer below!

After many searches and debugging, I believe that this is the right way to determine if Wi-Fi is connected or disconnected.

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

Together with the next receiver element in 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> 

Some explanation:

  • When I consider only ConnectivityManager.CONNECTIVITY_ACTION , I always get two intentions containing identical NetworkInfo instances (both getType () == TYPE_WIFI and isConnected () == true) when connecting over Wi-Fi - the problem described in this question.

  • When only WifiManager.NETWORK_STATE_CHANGED_ACTION , when disconnecting Wifi, the intent is not transmitted, but two intentions containing different instances of NetworkInfo, which allow to determine one event when connecting Wifi.

NOTE. I got one report on intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO) NPE) in which intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO) returned intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO) . Thus, even if this happens extremely rarely, it would be nice to add a null check.

Hurray, Torsten

+61
May 04 '11 at 21:31
source share

If you listen to WifiManager.NETWORK_STATE_CHANGED_ACTION , you will get it twice because there are two methods in NetworkInfo

  • isConnectedOrConnecting()
  • isConnected()

The first time isConnectedOrConnecting() returns true and isConnected() false
Second time isConnectedOrConnecting() and isConnected() return true

Greetings

+12
06 Sep '11 at 20:27
source share

The Torsten code has been updated so that when WIFI is turned off, only one corresponding broadcast is valid.

For verification, NetworkInfo.getDetailedState () == DetailedState.DISCONNECTED is used.

 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)); } } } 
+4
Jun 25 '13 at 6:29
source share

If you register an activity as a receiver of intentions, you will receive the same message twice. In particular, you need to choose whether you want to listen to the package level (XML) or the software level.

If you set up the class for the broadcast receiver and connect it to the listening And you attach the intent filter to the activity, then the message will be replicated twice.

Hope this solves your problem.

+3
May 04 '11 at 21:49
source share

I decided to call twice using SharedPref over 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 no network connectivity"); } } 

Because there is a slight delay between 1.call and 2.call (about 200 milisec). Thus, in IF, over time, the second call will stop and only be continued first.

+2
Aug 14 '14 at 21:31
source share

I decided that with in

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

at

 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; } } 
+2
Aug 26 '15 at 21:16
source share

This is the correct way to register connection changes in API 21 and later. The following code can be placed in the base action, and so you can expect that every screen in your application (which inherits from this action) will receive these callbacks.

First create a network callback that will track connection changes.

 @TargetApi(Build.VERSION_CODES.LOLLIPOP) private val networkCallback: ConnectivityManager.NetworkCallback = object : ConnectivityManager.NetworkCallback() { // Implement the callback methods that are relevant to the actions you want to take. // I have implemented onAvailable for connecting and onLost for disconnecting. override fun onAvailable(network: Network?) { super.onAvailable(network) } override fun onLost(network: Network?) { super.onLost(network) } } 

Then register and unregister in the appropriate places.

 override fun onResume() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager cm?.registerNetworkCallback(NetworkRequest.Builder().build(), networkCallback) } } 

And unregister when necessary.

 override fun onPause() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager cm?.unregisterNetworkCallback(networkCallback) } } 

Note that there is a check for Build.VERSION_CODES.LOLLIPOP . This functionality is only available in Lollipop and above. Make sure you have a plan for handling network state changes on Pre-Lollipop devices if you support less than 21 APIs in your application.

+2
Feb 05 '19 at 16:29
source share

I solved this problem using additional intentions for NetworkInfo. In the example below, the onReceive event is fired only once if Wi-Fi is connected or mobile.

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

and my assistant:

  public static boolean isNetworkConnected(Context ctx) { ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo ni = cm.getActiveNetworkInfo(); return ni != null; } 
+1
Feb 11 '17 at 14:00
source share

If you want to receive it only once, you can simply control it through 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 data plan } isUpdated = true; } else { isUpdated = false; } } } 
+1
Apr 28 '18 at 6:28
source share

The way I dealt with this was simply saving the state of the network and then comparing it to see if a change had occurred.

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

If this is your approach, it is important to reset it in the onResume your fragment or action so that it retains the current value:

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

I did this in my BaseFragment , the parent of all the fragments in my application.

0
Mar 23 '15 at 18:57
source share

check networkType from intent and 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 } } 
0
Sep 29 '16 at 1:09
source share

I found a special case for connecting to the network, saying that there is no Internet, but actually there is. It turns out that getActiveNetworkInfo will always return DISCONNECTED / BLOCKED in the specific case when the network changes, when the battery level is low, and the application was simply switched.

Mark this post

0
Jul 21 '17 at 7:48
source share

When you turn on WIFI,

  1. When MOBILE data is turned on, two broadcasts are sent: broadcast No. 1: MOBILE data is disabled, and broadcast No. 2: WIFI connection
  2. With MOBILE data OFF, only one broadcast sent: Broadcast # 1: WIFI connected

A similar behavior can be observed when turning off Wi-Fi in the two above conditions.

To distinguish between them, follow No. 2 and No. 3 below:

  @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"); } } } 
0
Sep 14 '18 at 16:29
source share

Listen only to the action "android.net.conn.CONNECTIVITY_CHANGE". It is broadcast whenever a connection is established or terminated.

"android.net.wifi.STATE_CHANGE" will be broadcast when the connection is established. That way you get two triggers.

Enjoy it!

-2
Oct 19 2018-11-11T00:
source share



All Articles