CONNECTIVITY_ACTION意图在WiFi连接时收到两次

在我的应用程序中,我有一个BroadcastReceiver ,通过<receiver>标记作为组件启动,过滤android.net.conn.CONNECTIVITY_CHANGE意图。

我的目标是简单地知道什么时候build立了Wifi连接,所以我在onReceive()做的是这样的:

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

它工作正常,但我似乎总是在build立一个Wifi连接约一秒钟之内得到两个相同的意图。 我试图查看任何信息,我可以从意图, ConnectivityManagerWifiManager ,但我找不到任何区别两个意图。

查看日志,至less有一个其他BroadcastReceiver也收到两个相同的意图。

它运行在Android 2.2的HTC Desire上

任何想法,为什么我似乎得到一个“重复”的意图,当Wifi连接或两者之间的差异可能是什么?

经过大量的search和debugging,我相信这是确定Wifi是否连接或断开的正确方法。

BroadcastReceiver中的onReceive()方法:

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

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

一些解释:

  • 当只考虑ConnectivityManager.CONNECTIVITY_ACTION ,当Wifi连接时,我总是得到包含相同NetworkInfo实例的两个intent(getType()== TYPE_WIFI和isConnected()== true),这个问题描述了这个问题。

  • 当仅使用WifiManager.NETWORK_STATE_CHANGED_ACTION ,在Wifi断开连接时没有意图广播,但是包含不同NetworkInfo实例的两个意图允许在连接Wifi时确定一个事件。

注:我收到一个单一的崩溃报告(NPE) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO)返回null。 所以,即使这种情况发生的可能性非常小,添加一个空检查可能是一个好主意。

干杯,Torsten

如果您正在监听WifiManager.NETWORK_STATE_CHANGED_ACTION您将收到这两次,因为NetworkInfo有两种方法

  • isConnectedOrConnecting()
  • isConnected()

第一次isConnectedOrConnecting()返回trueisConnected()返回false
第二次isConnectedOrConnecting()isConnected()返回true

干杯

更新了Torsten的代码,这样当WIFI断开连接时,只有一个合适的广播被执行。

使用NetworkInfo.getDetailedState()== DetailedState.DISCONNECTED进行检查。

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

如果您将活动注册为意向侦听器,则您将收到相同的消息两次。 具体而言,您需要select是要在包级别(XML)还是在编程级别上进行监听。

如果您为广播接收者设置了一个类并附加了监听,并且您将一个意图filter附加到该活动,则该消息将被复制两次。

我希望这可以解决你的问题。

我使用SharedPref和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"); } } 

因为在1.call和2.call(大约200 milisec)之间有小的延迟。 所以如果随着时间的推移第二个电话将停止,只是第一个将继续。

我解决了如果与

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

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

我通过使用NetworkInfo的意图额外解决了这个问题。 在下面的例子中,如果wifi连接或移动,onReceive事件只被触发一次。

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

和我的帮手:

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

我处理这个问题的方法就是简单地保存networking的状态,然后比较它是否有变化

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

如果这是你采取的方法,重要的是重置它的片段或活动的onResume ,以便它保持当前值:

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

我在我的应用程序的所有片段的父母BaseFragment做到了这一点。

从意图检查networkType并比较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 } } 

发现一个networking连接的特殊情况,说没有互联网,但实际上有。 事实certificate, getActiveNetworkInfo将始终返回您断开/阻塞在一个特定的情况下,当电池电量不足,而应用程序刚刚切换

看看这个post

只听动作“android.net.conn.CONNECTIVITY_CHANGE”。 连接build立或销毁时播放。

build立连接时会播放“android.net.wifi.STATE_CHANGE”。 所以你得到两个触发器。

请享用!