Android internet connectivity check - android

am trying to check for available internet connection, i find many subjects speaking about this, but i still have a problem when i try to verify for the internet connection, the code am using is the flowing:
public boolean isOnline() {
ConnectivityManager conMgr =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr.getActiveNetworkInfo() != null && conMgr.getActiveNetworkInfo().isAvailable() && conMgr.getActiveNetworkInfo().isConnected()) {
return true;
} else {
return false;
}
}
How can help me please ?
PS: Sorry for my bad English.

Your method is correct. Also you'll need in your android manifest file:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
But keep in mind that low signal, server downtime, captive portals, content filters, other network problems can prevent your application from reaching a server. So having an active network interface doesn't guarantee that a particular networked service is available.

In this code you have red status in private var:
private boolean mIsConnected;
#Override
protected void onResume()
{
super.onResume();
//red status broadcast
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(mNetworkStateReceiver, filter);
}
private BroadcastReceiver mNetworkStateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
NetworkInfo networkInfo =
(NetworkInfo)intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
mIsConnected= networkInfo.isConnected();
Log.i("TAG", String.format("Status red: %b", mIsConnected))
}
};

Related

Race condition when detecting connectivity status change in Android

I need to monitor and determine connectivity status changes in my Android app. For that, I have registered my class as a broadcast receiver:
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(this, filter);
Now, for determining the connectivity status, you can do the following:
#Override
public void onReceive(Context context, Intent intent) {
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
return;
}
NetworkInfo aNetworkInfo =
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (aNetworkInfo == null) {
return;
}
boolean isConnected = aNetworkInfo.isConnected();
int networkType = aNetworkInfo.getType();
// by using isConnected & networkType, get the new connectivity status..
}
The issue is that ConnectivityManager.EXTRA_NETWORK_INFO is deprecated. Now, you are suggested to use the CONNECTIVITY_SERVICE with getActiveNetworkInfo(), something like that:
#Override
public void onReceive(Context context, Intent intent) {
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
return;
}
ConnectivityManager connManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connManager == null) {
return;
}
NetworkInfo activeNetworkInfo = connManager.getActiveNetworkInfo();
boolean isConnected =
(activeNetworkInfo != null) && activeNetworkInfo.isConnected();
int networkType =
(activeNetworkInfo != null) ? activeNetworkInfo.getType() : -1;
// by using isConnected & networkType, get the new connectivity status..
}
This raises the following question:
In the 2nd implementation, when using the CONNECTIVITY_SERVICE and not the EXTRA_NETWORK_INFO:
Is there a chance for a race condition? As the onReceive is called asynchronously, when getting the network info from the connectivity service, may the connectivity state be different from the network info in the intent (as the connectivity might change in the meanwhile)?
Meaning, when using the intent, I am sure that the network info includes the data that triggered the onReceive, but when using the service - the network info might be different...?
If so, what's the best way to get the info that triggered the onReceive?
Also, if the only way to do so is to keep using the intent - doesn't that make 2 sources of truth? (one from the Connectivity Service, and one from the sent intent...)
UPDATE:
An example of the possible race condition:
Someone connected to WiFi and immediately disconnected from WiFi. This will result in 2 intents to be sent (one for connected to WiFi, and one for disconnecting from WiFi. More intents are actually sent, but I will focus on these 2). The possible race condition I am asking about is that: when we get the first intent (WiFi connected), the intent extra EXTRA_NETWORK_INFO will result in isConnected = true and networkType = TYPE_WIFI. But, is it possible that when I get the data from the Connectivity Service, as the onReceive is called asynchronously, the WiFi has already disconnected, resulting in isConnected = false and networkType = TYPE_WIFI while the intent still holds the right values for this call of onReceive? Or this will always happen fast enough so you get the right values from the Connectivity Service in the onReceive.. ?
My solution was sending a broadcast everytime connection changes adding an extra if the status of connection is up or down, hope it helps:
public class ConnectivityChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(context.getClass().getName(), " Changed connection ");
context.sendBroadcast(new Intent(MyApplication.ACTION_CONNECTION_CHANGED)
.putExtra(MyApplication.INTENT_EXTRA_CONNECTION_STATUS,NetWorkUtils.isNetworkAvailable(context)));
}}
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
}
Android manifest:
<receiver android:name=".ConnectivityChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>

Start service when internet is active in android

How to start a service when internet is enabled?
I need to start the service when the internet is active state. I have application that communicate with the web application when internet is present,even offline the mobile need a communication,it will known by server at the time of internet comes active.
The answer is in your question. Just create a BroadcastReceiver to listen network state, when internet is okay, start server as usual.
public class NetworkBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
ConnectivityManager mgr = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = mgr.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isConnected()){
isNetworkConnected = true;
//do your work here
}
}
}}

checking Network Status while running the app in android

I am streaming a video by using some url. Here, when i started the application I have checked the network status, or when i came to onResume state, i checked the Network status. But , while streaming is playing, If any cause net work will fail.. How can i check the status of the Network.
Here i am using this code for check the status..
public static boolean isOnline(Context context) {
boolean state = false;
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifiNetwork =
cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (wifiNetwork != null) {
state=wifiNetwork.isConnectedOrConnecting();
}
NetworkInfo mobileNetwork =
cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (mobileNetwork != null) {
state=mobileNetwork.isConnectedOrConnecting();
}
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (activeNetwork != null) {
state=activeNetwork.isConnectedOrConnecting();
}
return state;
}
from oncreate and orResume method, i was calling this method.. But how can i find the status of Network while running the app.
Thanks in advance...
You can register a BroadcastReceiver inside your Activity, that will receive the connectivity change broadcast. So inside the onReceive() method, that will be triggered when there will be a change in your connectivity, you will have to take actions :
BroadcastReceiver mNetworkReceiver=new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//take actions
}
};
registerReceiver(mNetworkReceiver,
new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
You will also need to add the following permission to your manifest :
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />

How to detect when WIFI Connection has been established in Android?

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.
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();
}
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"/>
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
}
}
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);
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"/>
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:)
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
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.
November 2020:
I have dealt too much with items deprecated by Google. Finally I found a solution to my particular requirement using "registerNetworkCallback" as Google currently suggests.
What I needed was a simple way to detect that my device has an IPv4 assigned in WIFI.
(I haven't tried other cases, my requirement was very specific, but maybe this method, without deprecated elements, will serve as a basis for other cases).
Tested on APIs 23, 24 and 26 (physical devices) and APIs 28 and 29 (emulated devices).
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.
}
}
);
(Implemented inside "MainActivity.Oncreate")
Note: In manifest needs "android.permission.ACCESS_NETWORK_STATE"
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;
}
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();
}
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.
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
}
}
}
};
}
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
You Can use Broadcast With Filter
<receiver
android:name=".receivers.ConnectionType"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
after that, you can listen to the value returned like that
#Override
public void onReceive(Context context, Intent intent) {
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
if(wifiState==WifiManager.WIFI_STATE_ENABLED){
Toast.makeText(context, "WIFI on", Toast.LENGTH_SHORT).show();
}else if(wifiState==WifiManager.WIFI_STATE_DISABLED) {
Toast.makeText(context, "WIFI OFF", Toast.LENGTH_SHORT).show();
}
}
it will fire every time WIFI enabled or disabled

CONNECTIVITY_ACTION intent received twice when Wifi connected

In my app I have a BroadcastReceiver that is launched as a component through a <receiver> tag, filtering android.net.conn.CONNECTIVITY_CHANGE intents.
My goal is simply to know when a Wifi connection was established, so what I am doing in onReceive() is this:
NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.isConnected()) {
// Wifi is connected
}
It works fine, but I always seem to get two identical intents within about one second when a Wifi connection is established. I tried to look at any info I could get from the intent, the ConnectivityManager and WifiManager, but I can't find anything that distinguishes the two intents.
Looking at the log, there is at least one other BroadcastReceiver that also receives the two identical intents.
It is running on a HTC Desire with Android 2.2
Any idea why I seem to get a "duplicated" intent when Wifi connects or what the difference between the two might be?
NOTE: For a recent, up-to-date answer, see this one below!
After a lot of googling and debugging, I believe this is the correct way to determine if Wifi has connected or disconnected.
The onReceive() method in the 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));
}
}
}
Together with the following receiver element in 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>
Some explanation:
When only considering ConnectivityManager.CONNECTIVITY_ACTION, I always get two intents containing identical NetworkInfo instances (both getType() == TYPE_WIFI and isConnected() == true) when Wifi connects - the issue described in this question.
When only using WifiManager.NETWORK_STATE_CHANGED_ACTION, there is no intent broadcasted when Wifi disconnects, but two intents containing different NetworkInfo instances, allowing to determine one event when Wifi is connected.
NOTE: I've received one single crash report (NPE) where the intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO) returned null. So, even if it seems to be extremely rare to happen, it might be a good idea to add a null check.
Cheers,
Torsten
If you're listening on WifiManager.NETWORK_STATE_CHANGED_ACTION you'll receive this twice because there are 2 methods in the NetworkInfo
isConnectedOrConnecting()
isConnected()
First time isConnectedOrConnecting() returns true and isConnected() false
Second time isConnectedOrConnecting() and isConnected() return true
Cheers
This is the proper way to register for connectivity changes on API 21 and higher. The following code can be placed in a base activity and that way you can expect every screen in your app (that inherits from this activity) to get these callbacks.
First, create a network callback which will monitor connectivity changes.
#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)
}
}
Then, register and unregister this callback in the relevant spots.
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)
}
}
And unregister when appropriate.
override fun onPause() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
cm?.unregisterNetworkCallback(networkCallback)
}
}
Notice that there is a check for Build.VERSION_CODES.LOLLIPOP. This functionality is only available in Lollipop and above. Be sure to have a plan for how to handle network status changes in Pre-Lollipop devices if you support less than API 21 in your app.
Updated the code of Torsten, such that when WIFI gets disconnected, only the single appropriate broadcast is acted upon.
Used NetworkInfo.getDetailedState() == DetailedState.DISCONNECTED for the checking.
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.getDetailedState() == DetailedState.DISCONNECTED) {
// Wifi is disconnected
Log.d("Inetify","Wifi is disconnected: "+String.valueOf(networkInfo));
}
}
}
If you registered the activity as an intent listener then you will recieve the same message twice. Specifically, you need to choose whether you want to listen on the Package level (XML) or the programatic level.
If you set up a class for a broadcast reciever and attach the listen to it AND you attach an intent filter to the activity, then the message will be replicated twice.
I hope this solves your issue.
I solved twice call by using SharedPref with Time.
private static final Long SYNCTIME = 800L;
private static final String LASTTIMESYNC = "DATE";
SharedPreferences sharedPreferences;
private static final String TAG = "Connection";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Network connectivity change");
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
final ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo ni = connectivityManager.getActiveNetworkInfo();
if (ni != null && ni.isConnected()) {
if(System.currentTimeMillis()-sharedPreferences.getLong(LASTTIMESYNC, 0)>=SYNCTIME)
{
sharedPreferences.edit().putLong(LASTTIMESYNC, System.currentTimeMillis()).commit();
// Your code Here.
}
}
else if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE)) {
Log.d(TAG, "There's no network connectivity");
}
}
Because there is small delay between 1.call and 2.call (About 200 milisec).
So in IF with time second call will stop and just first will continue.
I solved if with
in
onCreate()
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
intentFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
intentFilter.addAction("android.net.wifi.STATE_CHANGE");
ctx.registerReceiver(outgoingReceiver, intentFilter);
in
BroadcastReceiver
public void onReceive(Context context, Intent intent) {
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 connected
Log.d("Inetify", "Wifi is connected: " + String.valueOf(networkInfo));
Log.e("intent action", intent.getAction());
if (isNetworkConnected(context)){
Log.e("WiFi", "is Connected. Saving...");
try {
saveFilesToServer("/" + ctx.getString(R.string.app_name).replaceAll(" ", "_") + "/Temp.txt");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}}
boolean isNetworkConnected(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni != null) {
Log.e("NetworkInfo", "!=null");
try{
//For 3G check
boolean is3g = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
.isConnectedOrConnecting();
//For WiFi Check
boolean isWifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
.isConnected();
Log.e("isWifi", "isWifi="+isWifi);
Log.e("is3g", "is3g="+is3g);
if (!isWifi)
{
return false;
}
else
{
return true;
}
}catch (Exception er){
return false;
}
} else{
Log.e("NetworkInfo", "==null");
return false;
}
}
I solved this problem by using the intent extra for NetworkInfo.
In the example below, onReceive event is fired only once if wifi is connected or mobile.
if (intent.getAction().equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean screenIsOn = false;
// Prüfen ob Screen on ist
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
screenIsOn = pm.isInteractive();
} else {
screenIsOn = pm.isScreenOn();
}
if (Helper.isNetworkConnected(context)) {
if (networkInfo.isConnected() && networkInfo.isAvailable()) {
Log.v(logTAG + "onReceive", "connected");
if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
Log.v(logTAG + "onReceive", "mobile connected");
} else if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
Log.v(logTAG + "onReceive", "wifi connected");
}
}
}
and my helper:
public static boolean isNetworkConnected(Context ctx) {
ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
return ni != null;
}
If you only want to receive it once, you can simply control it through variables.
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
NetworkInfo activeNetwork = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (activeNetwork != null) { // connected to the internet
if (activeNetwork.isConnected() && !isUpdated) {
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
// connected to wifi
} else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
// connected to the mobile provider's data plan
}
isUpdated = true;
} else {
isUpdated = false;
}
}
}
When turning WIFI ON,
With MOBILE data ON, two broadcasts are sent:
Broadcast #1 : MOBILE data disconnected, and
Broadcast #2 : WIFI connected
With MOBILE data OFF, only one broadcast is sent:
Broadcast #1 : WIFI connected
Similar behavior can be observed while turning the WIFI OFF under the above two conditions.
To distinguish between the two, please follow #2 and #3 below:
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "*** Action: " + intent.getParcelableExtra("networkInfo"));
NetworkInfo netInfo = intent.getParcelableExtra("networkInfo");
if(intent.getAction().equalsIgnoreCase("android.net.conn.CONNECTIVITY_CHANGE")) {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null) {
if (netInfo.getType() == ConnectivityManager.TYPE_WIFI) {
if (netInfo.getState().name().contains("DISCONNECTED")
&& activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
Log.d(TAG, "WIFI disconnect created this broadcast. MOBILE data ON."); // #1
} else if (netInfo.getState().name().contains("CONNECTED")
&& activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
Log.d(TAG, "WIFI connect created this broadcast."); // #2
}
} else if (netInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
if (netInfo.getState().name().contains("DISCONNECTED")
&& activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
Log.d(TAG, "MOBILE data disconnect created this broadcast. WIFI ON."); // #3
} else if (netInfo.getState().name().contains("CONNECTED")
&& activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
Log.d(TAG, "MOBILE data connect created this broadcast."); // #4
}
}
} else {
Log.d(TAG, "No network available");
}
}
}
The way I handled it, was simply by saving the state of the network and then comparing it to see if there was a change.
public class ConnectivityChangedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
boolean previouslyConnected = MyApp.getInstance().isNetworkPreviouslyConnected();
boolean currentlyConnected = MyApp.getInstance().isNetworkConnected();
if (previouslyConnected != currentlyConnected) {
// do something and reset
MyApp.getInstance().resetNetworkPreviouslyConnected();
}
}
}
If this is the approach you take, it's important to reset it in onResume of your fragment or activity, so that it holds the current value:
#Override
public void onResume() {
super.onResume();
MyApp.getInstance().resetNetworkPreviouslyConnected();
}
I did that in my BaseFragment, a parent of all fragments in my app.
check networkType from intent
and compare activeNetworkInfo.getType()
Bundle bundle = intent.getExtras();
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = manager.getActiveNetworkInfo();
if(ni != null && ni.getState() == NetworkInfo.State.CONNECTED) {
if(bundle.getInt("networkType") == ni.getType()) {
// active network intent
}
}
Found a special case for network connectivity saying there is no internet but actually there is. It turns out getActiveNetworkInfo will always return you DISCONNECTED/BLOCKED in a specific case when network is changed while battery level is low and app was just switched
Check out this post
Only listen to action "android.net.conn.CONNECTIVITY_CHANGE". It's broadcasted whenever connection is established or destroyed.
"android.net.wifi.STATE_CHANGE" will be broadcasted when connection established. So you get two triggers.
Enjoy!

Categories

Resources