问题
I need to detect when I have network connectivity over WIFI. What broadcast is sent to establish that a valid network connection has been made. I need to validate that a valid network connection for HTTP exists. What should I listen for and what additional tests do I need to make to know that a valid connection exists.
回答1:
You can register a BroadcastReceiver to be notified when a WiFi connection is established (or if the connection changed).
Register the BroadcastReceiver
:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
registerReceiver(broadcastReceiver, intentFilter);
And then in your BroadcastReceiver
do something like this:
@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
}
}
}
For more info, see the documentation for BroadcastReceiver and WifiManager
Of course you should check whether the device is already connected to WiFi before this.
EDIT: Thanks to ban-geoengineering, here's a method to check whether the device is already connected:
private boolean isConnectedViaWifi() {
ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return mWifi.isConnected();
}
回答2:
The best that worked for me:
AndroidManifest
<receiver android:name="com.AEDesign.communication.WifiReceiver" >
<intent-filter android:priority="100">
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
BroadcastReceiver class
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();
}
}
}
Permissions
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
回答3:
For me only WifiManager.NETWORK_STATE_CHANGED_ACTION works.
Register a broadcast receiver:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
registerReceiver(broadcastReceiver, intentFilter);
and receive:
@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
}
}
回答4:
Answer given by user @JPM and @usman are really very useful. It works fine but in my case it come in onReceive
multiple time in my case 4 times so my code execute multiple time.
I do some modification and make as per my requirement and now it comes only 1 time
Here is java class for Broadcast.
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 ----- ");
}
}
}
}
In 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"/>
回答5:
You can start a wifi connection if you give the user a choice to override the normal behavior of asking each time.
I choose to use three methods...
public boolean isOnline()
{
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
This is quick check if there is an internet connect either Wifi or CellData. From here you can choose what action you want to take. Is it in Airplane mode needs to be checked also.
On a separate thread. I set a variable IpAddress to = " " And poll until I have a valid an ip address.
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);
Another code snippet... If its not on turn it on (with users prior permission)
if(wifi.isWifiEnabled()!=true)wifi.setWifiEnabled(true);
回答6:
To detect WIFI connection state, I have used CONNECTIVITY_ACTION from ConnectivityManager class so:
IntentFilter filter=new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(receiver, filter);
and from your 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:works fine for me:)
回答7:
This code does not require permission at all. It is restricted only to Wi-Fi network connectivity state changes (any other network is not taken into account). The receiver is statically published in the AndroidManifest.xml file and does not need to be exported as it will be invoked by the system protected broadcast, NETWORK_STATE_CHANGED_ACTION, at every network connectivity state change.
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 class:
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();
}
}
}
Permissions:
None
回答8:
Android O removed the possibility to receive the implicit broadcasts for a wifi state change. So if your app is closed, you'll not be able to receive them. The new WorkManager
has the ability to run when your app is closed, so I've experimented a bit with it and it seems to work quite well:
Add this to your dependencies:
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()
}
}
Keep in mind that this was just a quick test for a one-time notification. There is more work to do to always get notified when WiFi is turned on and off.
PS: When the app is force quit, the worker is not started, it seems WorkManager
is canceling the requests then.
回答9:
Here is an example of my code, that takes into account the users preference of only allowing comms when connected to Wifi.
I am calling this code from inside an IntentService
before I attempt to download stuff.
Note that NetworkInfo
will be null
if there is no network connection of any kind.
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;
}
回答10:
I used this code:
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
}
}
}
};
}
回答11:
I have two methods to detect WIFI connection receiving the application context:
1)my old method
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;
}
2)my New method (I´m currently using this method):
public boolean isConnectedWifi(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return networkInfo.isConnected();
}
回答12:
1) I tried Broadcast Receiver approach as well even though I know CONNECTIVITY_ACTION/CONNECTIVITY_CHANGE is deprecated in API 28 and not recommended. Also bound to using explicit register, it listens as long as app is running.
2) I also tried Firebase Dispatcher which works but not beyond app killed.
3) Recommended way found is WorkManager to guarantee execution beyond process killed and internally using registerNetworkRequest()
The biggest evidence in favor of #3 approach is referred by Android doc itself. Especially for apps in the background.
Also here
In Android 7.0 we're removing three commonly-used implicit broadcasts — CONNECTIVITY_ACTION, ACTION_NEW_PICTURE, and ACTION_NEW_VIDEO — since those can wake the background processes of multiple apps at once and strain memory and battery. If your app is receiving these, take advantage of the Android 7.0 to migrate to JobScheduler and related APIs instead.
So far it works fine for us using Periodic WorkManager request.
Update: I ended up writing 2 series medium post about it.
回答13:
For all those who enjoying CONNECTIVITY_CHANGE broadcast, please note this is no more fired when app is in background in Android O.
https://developer.android.com/about/versions/o/background.html
来源:https://stackoverflow.com/questions/5888502/how-to-detect-when-wifi-connection-has-been-established-in-android