我需要检测何时可以通过WIFI进行网络连接。发送什么广播以建立有效的网络连接。我需要验证是否存在用于HTTP的有效网络连接。我应该听什么以及需要进行哪些其他测试才能知道存在有效的连接。
我需要检测何时可以通过WIFI进行网络连接。发送什么广播以建立有效的网络连接。我需要验证是否存在用于HTTP的有效网络连接。我应该听什么以及需要进行哪些其他测试才能知道存在有效的连接。
Answers:
您可以注册一个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(); }
最适合我的:
<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次了
这是广播的java类。
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 ----- ");
}
}
}
}
在AndroidManifest中
<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"/>
你可以,如果你给用户一个选择,覆盖每一次询问的正常行为启动WiFi连接。
我选择使用三种方法...
public boolean isOnline()
{
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
这是快速检查是否有Internet连接Wifi或CellData。在这里,您可以选择要采取的措施。是否处于飞行模式也需要检查。
在单独的线程上。我将变量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);
要检测WIFI连接状态,我使用了ConnectivityManager类中的CONNECTIVITY_ACTION,因此:
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:对我来说很好:)
此代码完全不需要权限。仅限于Wi-Fi网络连接状态更改(不考虑任何其他网络)。接收机静态发布在AndroidManifest.xml文件中,并不需要被导出,因为它会被系统调用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
这是我的代码示例,其中考虑了用户在连接到Wifi时仅允许通讯的偏好。
IntentService
在尝试下载内容之前,我从内部调用了此代码。
请注意,如果没有任何类型的网络连接,NetworkInfo
将会出现null
这种情况。
private boolean canConnect()
{
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
boolean canConnect = false;
boolean wifiOnly = SharedPreferencesUtils.wifiOnly();
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if(networkInfo != null)
{
if(networkInfo.isConnected())
{
if((networkInfo.getType() == ConnectivityManager.TYPE_WIFI) ||
(networkInfo.getType() != ConnectivityManager.TYPE_WIFI && !wifiOnly))
{
canConnect = true;
}
}
}
return canConnect;
}
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时,还有更多工作要做以始终得到通知。
PS:当应用程序被强制退出时,工作程序尚未启动,似乎WorkManager
正在取消请求。
我使用以下代码:
public class MainActivity extends Activity
{
.
.
.
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
.
.
.
}
@Override
protected void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
registerReceiver(broadcastReceiver, intentFilter);
}
@Override
protected void onPause()
{
super.onPause();
unregisterReceiver(broadcastReceiver);
}
private final BroadcastReceiver broadcastReceiver = new 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))
{
// wifi is enabled
}
else
{
// wifi is disabled
}
}
}
};
}
我有两种方法来检测接收到应用程序上下文的WIFI连接:
public boolean isConnectedWifi1(Context context) {
try {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null) {
NetworkInfo[] netInfo = connectivityManager.getAllNetworkInfo();
for (NetworkInfo ni : netInfo) {
if ((ni.getTypeName().equalsIgnoreCase("WIFI"))
&& ni.isConnected()) {
return true;
}
}
}
return false;
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return false;
}
public boolean isConnectedWifi(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return networkInfo.isConnected();
}
对于所有喜欢CONNECTIVITY_CHANGE广播的用户,请注意,当应用程序在Android O中处于后台运行时,不再触发此操作。
https://developer.android.com/about/versions/o/background.html
1)即使我知道CONNECTIVITY_ACTION / CONNECTIVITY_CHANGE,我也尝试了广播接收器方法在API 28中已弃用,也不推荐使用,。此外,还必须使用显式寄存器,只要应用程序正在运行,它就会监听。
2)我还尝试了Firebase Dispatcher,它可以运行,但不能被应用杀死。
3)找到的推荐方法是WorkManager,以确保在进程被杀死之前和内部使用registerNetworkRequest()来确保执行
支持Android 3的最大证据是Android文档本身。尤其适用于后台应用程序。
也在这里
在Android 7.0中,我们删除了三个常用的隐式广播(CONNECTIVITY_ACTION,ACTION_NEW_PICTURE和ACTION_NEW_VIDEO),因为它们可以立即唤醒多个应用程序的后台进程,并占用大量内存和电池。如果您的应用程序收到这些消息,请利用Android 7.0迁移到JobScheduler和相关的API。
到目前为止,使用Periodical WorkManager请求对我们而言效果很好。
更新:我最终写了2系列有关它的中篇文章。