我需要检测我是否通过WIFI连接到网络。用于建立有效的网络连接的广播是什么?我需要验证HTTP的有效网络连接是否存在。我应该监听什么,还需要进行哪些额外的测试以确定存在有效的连接。
我需要检测我是否通过WIFI连接到网络。用于建立有效的网络连接的广播是什么?我需要验证HTTP的有效网络连接是否存在。我应该监听什么,还需要进行哪些额外的测试以确定存在有效的连接。
您可以注册一个 BroadcastReceiver
,以便在 WiFi 连接建立时(或连接更改时)收到通知。
注册 BroadcastReceiver
:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
registerReceiver(broadcastReceiver, intentFilter);
然后在你的BroadcastReceiver
中做如下操作:
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
//do stuff
} else {
// wifi connection was lost
}
}
}
更多信息请参见BroadcastReceiver
和WifiManager
文档。
当然,在此之前,您应该检查设备是否已连接到WiFi。
编辑:感谢ban-geoengineering,以下是一种检查设备是否已连接的方法:
private boolean isConnectedViaWifi() {
ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return mWifi.isConnected();
}
private boolean isConnectedViaWifi() {
ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return mWifi.isConnected();
}
- ban-geoengineering对我最有效的方法:
<receiver android:name="com.AEDesign.communication.WifiReceiver" >
<intent-filter android:priority="100">
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
public class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if(info != null && info.isConnected()) {
// Do your work.
// e.g. To check the Network Name or other info:
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String ssid = wifiInfo.getSSID();
}
}
}
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
只有WifiManager.NETWORK_STATE_CHANGED_ACTION
对我有用。
注册一个广播接收器:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
registerReceiver(broadcastReceiver, intentFilter);
并且收到:
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)){
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean connected = info.isConnected();
//call your method
}
}
用户@JPM和@usman提供的答案真的非常有用。它能够很好地工作,但在我的情况下,它在 onReceive 中出现多次,在我的情况下 4次,因此我的代码会多次执行。
我进行了一些修改,根据我的要求进行了调整,现在它只会出现1次。
这是Broadcast的Java类。
<strong><code>public class WifiReceiver extends BroadcastReceiver {
String TAG = getClass().getSimpleName();
private Context mContext;
@Override
public void onReceive(Context context, Intent intent) {
mContext = context;
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI &&
networkInfo.isConnected()) {
// Wifi is connected
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String ssid = wifiInfo.getSSID();
Log.e(TAG, " -- Wifi connected --- " + " SSID " + ssid );
}
}
else if (intent.getAction().equalsIgnoreCase(WifiManager.WIFI_STATE_CHANGED_ACTION))
{
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
if (wifiState == WifiManager.WIFI_STATE_DISABLED)
{
Log.e(TAG, " ----- Wifi Disconnected ----- ");
}
}
}
}
</code></strong>
在AndroidManifest中
<strong><code><receiver android:name=".util.WifiReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
</code></strong>
如果您允许用户选择覆盖每次询问的正常行为,则可以启动wifi连接。
我选择使用三种方法...
public boolean isOnline()
{
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
这是一次快速检查,以确定是否存在互联网连接,无论是Wi-Fi还是移动数据。在此基础上,您可以选择要采取的操作。还需要检查是否处于飞行模式。
在单独的线程中, 我将一个变量IpAddress设置=“”, 并进行轮询,直到我拥有有效的IP地址。
WifiManager wifi;
wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifi.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
String ip = null;
ip = String.format("%d.%d.%d.%d",
(ipAddress & 0xff),
(ipAddress >> 8 & 0xff),
(ipAddress >> 16 & 0xff),
(ipAddress >> 24 & 0xff));
Log.e(" >>IP number Begin ",ip);
另一段代码片段...如果它没有被打开,就把它打开(在用户先允许的情况下)
if(wifi.isWifiEnabled()!=true)wifi.setWifiEnabled(true);
IntentFilter filter=new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(receiver, filter);
并且从您的BroadCastReceiver:
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
int networkType = intent.getIntExtra(
android.net.ConnectivityManager.EXTRA_NETWORK_TYPE, -1);
if (ConnectivityManager.TYPE_WIFI == networkType) {
NetworkInfo networkInfo = (NetworkInfo) intent
.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (networkInfo != null) {
if (networkInfo.isConnected()) {
// TODO: wifi is connected
} else {
// TODO: wifi is not connected
}
}
}
}
PS: 对我来说工作得很好 :)
protected broadcast
,NETWORK_STATE_CHANGED_ACTION
。
AndroidManifest:
<receiver
android:name=".WifiReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<!--protected-broadcast: Special broadcast that only the system can send-->
<!--Corresponds to: android.net.wifi.WifiManager.NETWORK_STATE_CHANGED_ACTION-->
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
BroadcastReceiver类:
public class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
/*
Tested (I didn't test with the WPS "Wi-Fi Protected Setup" standard):
In API15 (ICE_CREAM_SANDWICH) this method is called when the new Wi-Fi network state is:
DISCONNECTED, OBTAINING_IPADDR, CONNECTED or SCANNING
In API19 (KITKAT) this method is called when the new Wi-Fi network state is:
DISCONNECTED (twice), OBTAINING_IPADDR, VERIFYING_POOR_LINK, CAPTIVE_PORTAL_CHECK
or CONNECTED
(Those states can be obtained as NetworkInfo.DetailedState objects by calling
the NetworkInfo object method: "networkInfo.getDetailedState()")
*/
/*
* NetworkInfo object associated with the Wi-Fi network.
* It won't be null when "android.net.wifi.STATE_CHANGE" action intent arrives.
*/
NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (networkInfo != null && networkInfo.isConnected()) {
// TODO: Place the work here, like retrieving the access point's SSID
/*
* WifiInfo object giving information about the access point we are connected to.
* It shouldn't be null when the new Wi-Fi network state is CONNECTED, but it got
* null sometimes when connecting to a "virtualized Wi-Fi router" in API15.
*/
WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
String ssid = wifiInfo.getSSID();
}
}
}
权限:
None
Android O移除了接收wifi状态改变的隐式广播的可能性。因此,如果您的应用程序已关闭,则无法接收它们。新的WorkManager
具有在应用程序关闭时运行的能力,因此我进行了一些实验,并且似乎工作得非常好:
将以下内容添加到您的依赖项中:
implementation "android.arch.work:work-runtime:1.0.0-alpha08"
WifiConnectWorker.kt
class WifiConnectWorker : Worker() {
override fun doWork(): Result {
Log.i(TAG, "I think we connected to a wifi")
return Result.SUCCESS
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val workManager = WorkManager.getInstance()
// Add constraint to start the worker when connecting to WiFi
val request = OneTimeWorkRequest.Builder(WifiConnectWorker::class.java)
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(UNMETERED)
.build())
.build()
// The worker should be started, even if your app is closed
workManager.beginUniqueWork("watch_wifi", REPLACE, request).enqueue()
}
}
请注意,这只是一次快速测试用于单次通知。还有更多工作需要做,以便在WiFi打开和关闭时始终收到通知。
附注:当应用程序被强制退出时,工作者未启动,似乎WorkManager
正在取消请求。
2020年11月:
我经常处理被Google废弃的项目。最终,我找到了一个解决方案来满足我的特定需求,使用了Google目前建议的"registerNetworkCallback"。
我所需要的是一种简单的方式来检测我的设备是否在WIFI网络中分配了IPv4地址。 (我还没有尝试其他情况,我的需求非常特殊,但也许这种方法可以作为其他情况的基础而不使用被废弃的元素)。
已在API 23、24和26(物理设备)以及API 28和29(模拟设备)上进行了测试。
ConnectivityManager cm
= (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
cm.registerNetworkCallback
(
builder.build(),
new ConnectivityManager.NetworkCallback()
{
@Override
public void onAvailable(Network network)
{
//Actions to take with Wifi available.
}
@Override
public void onLost(Network network)
{
//Actions to take with lost Wifi.
}
}
);
(在“MainActivity.Oncreate”中实现)
注意:在清单文件中需要添加“android.permission.ACCESS_NETWORK_STATE”。
onLost()
和onUnavailable()
都不会被调用。有什么建议吗? - Sam ChenBoolean
来指示连接状态并将其初始化为 false,好主意。 - Sam Chen1) 我尝试了Broadcast Receiver方法,即使我知道在API 28中已弃用CONNECTIVITY_ACTION/CONNECTIVITY_CHANGE并且不推荐使用。此外,它仅绑定到使用显式注册的应用程序,只要应用程序正在运行,它就会监听。
2) 我也尝试了Firebase Dispatcher,它可以工作,但无法在应用程序关闭后继续运行。
3) 推荐的方法是使用WorkManager来保证执行超过进程终止,并在内部使用registerNetworkRequest()
最大的支持#3方法的证据是由Android文档本身提供的。特别是对于后台中的应用程序。
还有在这里
在Android 7.0中,我们正在删除三个常用的隐式广播-- CONNECTIVITY_ACTION,ACTION_NEW_PICTURE和ACTION_NEW_VIDEO--因为这些广播可以同时唤醒多个应用程序的后台进程,并且会消耗内存和电池电量。 如果您的应用正在接收这些广播,请利用Android 7.0迁移到JobScheduler和相关API。
到目前为止,我们使用定期WorkManager请求很好地运行。
更新:最终我写了两篇系列关于此的中等文章。