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连接约一秒钟之内得到两个相同的意图。 我试图查看任何信息,我可以从意图, ConnectivityManager
和WifiManager
,但我找不到任何区别两个意图。
查看日志,至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()
返回true
, isConnected()
返回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”。 所以你得到两个触发器。
请享用!