连接Wifi时,CONNECTIVITY_ACTION意图收到两次

Tor*_*mer 50 android android-wifi android-broadcastreceiver

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

我的目标只是知道何时建立了Wifi连接,所以我在做的onReceive()是:

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

它工作正常,但在建立Wifi连接时,我似乎总是在大约一秒钟内得到两个相同的意图.我想看看任何信息,我可以从意图,获得ConnectivityManagerWifiManager,但我无法找到任何区别这两种意图.

查看日志,至少还有一个BroadcastReceiver也接收到两个相同的意图.

它运行在搭载Android 2.2的HTC Desire上

任何想法为什么我似乎在Wifi连接时获得"重复"的意图或两者之间的差异可能是什么?

Tor*_*mer 62

经过大量的谷歌搜索和调试后,我相信这是确定Wifi连接或断开连接的正确方法.

onReceive()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));
    }
}
}
Run Code Online (Sandbox Code Playgroud)

与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>
Run Code Online (Sandbox Code Playgroud)

一些解释:

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

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

注意:我收到一个崩溃报告(NPE),其中intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO)返回null.因此,即使它似乎极少发生,添加空检查也许是个好主意.

干杯,托斯滕

  • 我想在此提一下,至少有时候,在完全建立数据连接(DHCP配置未完成)之前,WifiManager.NETWORK_STATE_CHANGED_ACTION`意图会在短时间内广播,并且在那时,`ConnectivityManager.getActiveNetworkInfo( )`可能仍会返回类型为"TYPE_WIFI"的`NetworkInfo`. (3认同)

Dom*_*rtl 12

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

  • isConnectedOrConnecting()
  • isConnected()

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

干杯

  • 这两个方法对我来说两个事件都返回true (9认同)

Mik*_*ike 7

这是在 API 21 及更高版本上注册连接更改的正确方法。以下代码可以放置在基本活动中,这样您就可以期望应用程序中的每个屏幕(从该活动继承)都获得这些回调。

首先,创建一个网络回调来监控连接变化。

@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)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在相关位置注册和取消注册此回调。

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

并在适当的时候取消注册。

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

请注意,有一个检查Build.VERSION_CODES.LOLLIPOP。此功能仅适用于 Lollipop 及更高版本。如果您的应用支持的 API 低于 21,请务必制定如何处理 Pre-Lollipop 设备中网络状态更改的计划。