Wifi连接-断开监听器

57
我的类需要实现哪个监听器才能在wifi连接/断开时自动检查代码?
我能够手动检查wifi的连接/断开状态,但每次我都需要从Android设置中连接/断开Wifi,然后运行我的程序才能得到结果。
我的当前代码很简单:
WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
if (wifi.isWifiEnabled()==true)
{
    tv.setText("You are connected");
}
else
{
    tv.setText("You are NOT connected");
}
7个回答

80

实际上,您正在检查Wi-Fi是否已启用,这并不一定意味着它已连接。这只是意味着手机上的Wi-Fi模式已启用并能够连接到Wi-Fi网络。

以下是我在广播接收器中监听实际Wi-Fi连接的方式:

public class WifiReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {     
        ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
        NetworkInfo netInfo = conMan.getActiveNetworkInfo();
        if (netInfo != null && netInfo.getType() == ConnectivityManager.TYPE_WIFI) 
            Log.d("WifiReceiver", "Have Wifi Connection");
        else
            Log.d("WifiReceiver", "Don't have Wifi Connection");    
    }   
};

为了访问活动网络信息,您需要将以下uses-permission添加到AndroidManifest.xml中:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

以下是意图接收器(或您可以通过编程方式添加...)

<!-- Receive Wi-Fi connection state changes -->
<receiver android:name=".WifiReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

编辑:在Lollipop中,如果您想要在用户连接到非计量网络连接时执行某个操作,则可以使用作业调度。请参考:http://developer.android.com/about/versions/android-5.0.html#Power


编辑2:另一个需要考虑的问题是我的答案没有检查您是否连接到互联网。您可能连接到需要登录的Wi-Fi网络。这里有一个有用的“IsOnline()”检查:https://dev59.com/bnI_5IYBdhLWcg3wBuRs#27312494


这很棒,但我该如何在我的活动中使用它? - sabsab
它被称为“twice”。我收到了两次这个消息,WifiReceiver:已连接Wifi。 - Qadir Hussain
android.net.conn.CONNECTIVITY_CHANGE已被弃用。现在的解决方案是什么? - Sourav Bagchi
如果您需要接收通知(并且您的目标是N或更高版本),则必须在应用程序内注册接收器,而不是在清单文件中注册,这意味着您的应用程序必须已经在运行。请参阅https://dev59.com/eFkT5IYBdhLWcg3wFryj的答案。或者您可以尝试使用作业调度。 - warbi
conMan 变量 +1 - Aaron Lelevier
1
如前所述,android.net.conn.CONNECTIVITY_CHANGE现已被弃用。您可以在此处找到涉及非弃用代码的另一种解决方案:https://dev59.com/aFQJ5IYBdhLWcg3wdFZ4 - Peter Lehnhardt

18

创建一个继承自 BroadcastReceiver 的自定义类...

public class MyNetworkMonitor extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        // Process the Intent here

    }
}

在 AndroidManifest.xml 文件中

<receiver
    android:name=".MyNetworkMonitor" >
        <intent-filter>
            <action android:name="android.net.wifi.STATE_CHANGE" />
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
</receiver>

请参考WIFI_STATE_CHANGED_ACTIONCONNECTIVITY_ACTION,了解如何使用 Intent。


谢谢MisterSquonk。我会尝试的。 - Neha
那些变量来自WifiManager @Squonk? - gumuruh
@gumuruh WIFI_STATE_CHANGED_ACTION 属于 WifiManager 类,CONNECTIVITY_ACTION 属于 ConnectivityManager。您可能想要检查更多的连接类型,例如如果移动网络可用,则应请求激活网络,然后您可以获取 NetworkInfo(->type)ConnectionManager.TYPE_MOBILE... - Gödel77

15

请查看这两个JavaDoc页面:ConnectivityManagerWiFiManager

请注意,每个页面都定义了广播操作。如果您需要了解更多关于注册广播接收器的信息,请参考:程序化注册广播接收器

BroadcastReceiver receiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    if (wifi.isWifiEnabled()) {
      tv.setText("You are connected");
    } else {
      tv.setText("You are NOT connected");
    }
  }
};

如果你不想在代码中注册接收器,你可以在清单文件中这样做:

<application android:icon="@drawable/icon" android:label="@string/app_name">
    <receiver android:name=".WiFiReceiver" android:enabled="true">
        <intent-filter>
            <action android:name="android.net.ConnectivityManager.CONNECTIVITY_ACTION" />
        </intent-filter>
    </receiver>
</application>

编辑:

如果你只需要在应用程序运行时接收广播,那么最好在代码中注册该广播接收器,而不是在清单中注册。如果在清单中指定,则即使之前未运行过该进程,也会通知您的进程连接变化。

针对 Android 7.0(API 级别 24)及更高版本的应用程序,如果它们在清单中声明了广播接收器,则不会接收此广播。如果应用程序使用 android.content.Context#registerReceiver Context.registerReceiver() 注册其 android.content.BroadcastReceiver,并且该上下文仍然有效,则仍将接收广播。


1
我建议您编辑代码并明确引用上下文:“WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);”,否则如果在单独的类中使用“getSystemService()”,可能会出现错误。 - tony gil

5

我同意@tanner-perrien的回答,2020年,Kotlin代表着:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        registerReceiver(wifiBroadcastReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
    }

    private val wifiBroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
            Log.d("TUT", "Wifi is ${wifiManager.isWifiEnabled}")
        }
    }

    override fun onDestroy() {
        unregisterReceiver(wifiBroadcastReceiver)
        super.onDestroy()
    }
}

但是可能希望跟上时代的步伐:https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

活动:

lateinit var connec: ConnectivityManager

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    connec = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    val networkRequestWiFi = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .build()

    connec.registerNetworkCallback(networkRequestWiFi, networkCallbackWiFi)
 }

private var networkCallbackWiFi = object : ConnectivityManager.NetworkCallback() {
    override fun onLost(network: Network?) {
        Log.d("TUT", "WiFi disconnected")
    }

    override fun onAvailable(network: Network?) {
        Log.d("TUT", "WiFi connected")
    }
}

override fun onDestroy() {
    connec.unregisterNetworkCallback(networkCallbackWiFi)
    super.onDestroy()
}

什么是connec? - Sira Lam
1
抱歉,我漏掉了那个部分,已经添加回来了。 - Blundell
所以我看到这种新技术消除了注册广播接收器的需要。 :) - SMBiggs
是的,原始代码在第四行进行了注册。程序上的区别在于它不是在AndroidManifest中注册的。新的代码中,我们的应用程序没有广播接收器,也许框架会注册一个并将其转换为回调函数。 - Blundell

3
AndroidManifest.xml 文件中添加以下权限。
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

创建新的接收器类。
public class ConnectionChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager connectivityManager =
            (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();

        if (activeNetInfo != null
            && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
            Toast.makeText(context, "Wifi Connected!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, "Wifi Not Connected!", Toast.LENGTH_SHORT).show();
        }
    }

将该接收器类添加到 AndroidManifest.xml 文件中。
<receiver android:name="ConnectionChangeReceiver"
          android:label="NetworkConnection">
  <intent-filter>
    <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
  </intent-filter>
</receiver>

2

针对sabsab的回复。为了连接到网络连接状态变化的广播接收器,我使用了warbi的答案,并添加了一个包含静态方法的类。

public class WifiHelper
{
    private static boolean isConnectedToWifi;
    private static WifiConnectionChange sListener;

    public interface WifiConnectionChange {
        void wifiConnected(boolean connected);
    }

    /**
     * Only used by Connectivity_Change broadcast receiver
     * @param connected
     */
    public static void setWifiConnected(boolean connected) {
        isConnectedToWifi = connected;
        if (sListener!=null)
        {
            sListener.wifiConnected(connected);
            sListener = null;
        }
    }

    public static void setWifiListener(WifiConnectionChange listener) {
        sListener = listener;
    }
}

然后我对上面显示的第一个答案中的接收器类进行了更改。

public class ConnectivityReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
    ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = conMan.getActiveNetworkInfo();
    if (netInfo != null && netInfo.getType() == ConnectivityManager.TYPE_WIFI)
    {
        Log.d("WifiReceiver", "Have Wifi Connection");
        WifiHelper.setWifiConnected(true);
    } else
    {
        Log.d("WifiReceiver", "Don't have Wifi Connection");
        WifiHelper.setWifiConnected(false);
    }

}
}

最后,在您的活动中,您可以添加一个监听器来利用此回调函数。

wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
wasWifiEnabled = (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED || wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING);
WifiHelper.setWifiListener(new WifiHelper.WifiConnectionChange()
    {
        @Override
        public void wifiConnected(boolean connected)
        {
            //Do logic here
        }
    });

注意,回调函数触发后会移除监听器,这是因为它是一个静态监听器。无论如何,这个实现对我来说很有效,并且是一种钩入您的活动或任何地方(只要它是静态的)的方法。


0

还有WifiManager.NETWORK_STATE_CHANGED_ACTION

广播意图操作指示Wi-Fi连接状态已更改。额外提供新状态,以NetworkInfo对象的形式呈现。无需网络相关权限即可订阅此广播。

然后是getState(),它具有像CONNECTING / DISCONNECTING这样的状态,例如,CONNECTIVITY_ACTION没有。此外,CONNECTING表示没有互联网。 CONNECTED表示有互联网:https://android.googlesource.com/platform/frameworks/base/+/android10-release/core/java/android/net/NetworkInfo.java#122。或者有getDetailedState(),其中包括“无限”。

虽然自API 29起,NetworkInfo已被弃用,但对我来说似乎比在支持的设备上使用CONNECTIVITY_ACTION更好,因为它具有许多准确的状态。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接