I am implementing an app who needs an internet connection. If there is no internet connection, a "no connection" message will be displayed on different ways, depending on the activity.
To do this, I have the following class:
public class NetworkAvailability {
private static final String NETWORK_AVAILABILITY_ACTION = "com.toast.NETWORK_AVAILABILITY_ACTION";
private ConnectivityManager connectivityManager;
private ConnectivityManager.NetworkCallback networkCallback;
private static NetworkAvailability instance;
private NetworkAvailability() {
}
public static NetworkAvailability getInstance(){
if(instance == null){
instance = new NetworkAvailability();
}
return instance;
}
private static boolean isAvailable(Context context) {
ConnectivityManager cm =(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnected();
}
public void registerNetworkAvailability(final Context context, BroadcastReceiver networkAvailabilityReceiver) {
context.registerReceiver(networkAvailabilityReceiver, new IntentFilter(NETWORK_AVAILABILITY_ACTION));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
context.registerReceiver(connectivityChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
} else{
connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
networkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
context.sendBroadcast(getNetworkAvailabilityIntent(true));
}
#Override
public void onLost(Network network) {
context.sendBroadcast(getNetworkAvailabilityIntent(false));
}
};
connectivityManager.registerNetworkCallback(builder.build(), networkCallback);
if(isAvailable(context)){
context.sendBroadcast(getNetworkAvailabilityIntent(true));
} else{
context.sendBroadcast(getNetworkAvailabilityIntent(false));
}
}
}
public void unregisterNetworkAvailability(Context context, BroadcastReceiver networkAvailabilityReceiver){
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
context.unregisterReceiver(connectivityChangeReceiver);
} else{
connectivityManager.unregisterNetworkCallback(networkCallback);
}
context.unregisterReceiver(networkAvailabilityReceiver);
}
public BroadcastReceiver connectivityChangeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(#NonNull Context context, #NonNull Intent intent) {
if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
context.sendBroadcast(getNetworkAvailabilityIntent(false));
} else {
context.sendBroadcast(getNetworkAvailabilityIntent(true));
}
}
};
#NonNull
private Intent getNetworkAvailabilityIntent(boolean isNetworkAvailable) {
Intent intent = new Intent(NETWORK_AVAILABILITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, !isNetworkAvailable);
return intent;
}
}
How can I now use the BroadcastReceiver from each Activity?
What I did was setting the broadcastReceiver on the Manifest:
<receiver
android:name=".data.sync.CatchConnectionChangesReceiver"
android:label="Upload cached images broadcast receiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
Then I have the class:
class CatchConnectionChangesReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (Util.isNetworkAvailable()) {
// Do whatever you want to do when network is available
}
}
}
The receiver is going to be activated from every activity, you don´t need to register it on each
In Util.isNetworkAvailable() I have the same as in your isAvailable() method
Update according to first comment
If you want to do something like:
if (isConnected) {
// Do something here like view.setVisibility(View.Visible)
}
You just have your isAvailable() method public, as it´s already static, you can do this from any activity you want:
if (NetworkAvailability.isAvailable(this)) {
// Do something here like view.setVisibility(View.Visible)
}
For this last thing you do not need the broadcast receiver
Related
I want to write an event for different modes of Wi-Fi connection and mobile data.
If the Wi-Fi is on and the mobile data is off, the Wi-Fi icon will be visible
If the mobile data is on and the Wi-Fi is off, the mobile data icon will be visible
If both are on, both icons will be visible
If both are off, the icon will be gone
If both were on, and one of them went off, the icon that went off would go off
Exactly the same as the phone's system performance!
public class NetworkReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
final android.net.NetworkInfo wifiType = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo mobileType = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (wifiType.isConnectedOrConnecting()) {
wifi.setVisibility(View.VISIBLE);
} else if (mobileType.isConnectedOrConnecting()) {
data.setVisibility(View.VISIBLE);
} else if (wifiType.isConnectedOrConnecting() || mobileType.isConnectedOrConnecting()) {
wifi.setVisibility(View.VISIBLE);
data.setVisibility(View.VISIBLE);
} else {
wifi.setVisibility(View.GONE);
data.setVisibility(View.GONE);
}
}
}
You have to modify your code to work properly.
public class NetworkReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);
assert connectivityManager != null;
NetworkInfo[] activeNetworkInfo = connectivityManager.getAllNetworkInfo();
for (NetworkInfo ni : activeNetworkInfo) {
if (ni.getTypeName().equalsIgnoreCase("WIFI"))
if (ni.isConnected())
{
wifi.setVisibility(View.VISIBLE);
} else if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
if (ni.isConnected())
{
data.setVisibility(View.VISIBLE);
}else {
wifi.setVisibility(View.GONE);
data.setVisibility(View.GONE);
}
}
}
make sure that you add this line to your manifest:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
I think also that you mistaken when you add this code:
else if (wifiType.isConnectedOrConnecting() || mobileType.isConnectedOrConnecting()) {
wifi.setVisibility(View.VISIBLE);
data.setVisibility(View.VISIBLE);
}
It doesn't have any sense because you already test if one of them is connected so I suggest to change the code instead:
public class NetworkReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);
assert connectivityManager != null;
NetworkInfo[] activeNetworkInfo = connectivityManager.getAllNetworkInfo();
for (NetworkInfo ni : activeNetworkInfo) {
if (ni.getTypeName().equalsIgnoreCase("WIFI"))
if (ni.isConnected())
{
wifi.setVisibility(View.VISIBLE);
} else {
wifi.setVisibility(View.GONE);
}
if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
if (ni.isConnected())
{
data.setVisibility(View.VISIBLE);
}
else {
data.setVisibility(View.GONE);
}
}
}
I have a location tracking app. I have a Foreground service that when the app goes into the background, it continues to get the location. That part works fine. If I output the location I can see the different points and correct timestamps.
While in the background I need to POST that data to an API endpoint. My GPSHeartbeat class is a singleton and it exposes a function to let me update the Singletons location property.
While in the foreground, everything works fine. When in the background, the location IS updated, but the singleton has the last location from BEFORE it went into the background.
My APICommunicator is firing in the background on its interval like it should, it just doesn't have the correct Location.
Here is the broadcast receiver that is responsible for listening to the Foreground services location change.
This works fine in the background and in the foreground. It is successfully getting the updated location.
private void onNewLocation(Location location)
{
Log.i(TAG, "onNewLocationRec'd: " + location);
mLocation = location;
// Notify anyone listening for broadcasts about the new location.
Intent intent = new Intent(ACTION_BROADCAST);
intent.putExtra(EXTRA_LOCATION, location);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// Update notification content if running as a foreground service.
if (serviceIsRunningInForeground(this)) {
mNotificationManager.notify(NOTIFICATION_ID, getNotification());
}
}
The BroadcastReceiver is an inner class of an Activity called HomeActivity. This gets the CORRECT location from the service. If I output the log, it is the same as what the Service broadcast.
public class HomeActivity extends AppCompatActivity
{
private GPSHeartbeat mGPSHeartbeat;
private GPSReceiver myReceiver;
private LocationUpdatesService mService = null;
private boolean mBound = false;
private final ServiceConnection mServiceConnection = new ServiceConnection()
{
#Override
public void onServiceConnected(ComponentName name, IBinder service)
{
LocationUpdatesService.LocalBinder binder = (LocationUpdatesService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
mBound = false;
}
};
private void GPSBeginRequestingUpdates()
{
//Wait 5 seconds to spin up
(new Handler()).postDelayed(this::StartGPSUpdates, 5000);
}
private void StartGPSUpdates()
{
mService.requestLocationUpdates();
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
myReceiver = new GPSReceiver();
setContentView(R.layout.activity_home);
mGPSHeartbeat = GPSHeartbeat.instance(getApplicationContext()).setInterval(6);
}
#Override
protected void onStart()
{
super.onStart();
bindService(new Intent(getApplicationContext(), LocationUpdatesService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop()
{
if (mBound) {
unbindService(mServiceConnection);
mBound = false;
}
super.onStop();
}
#Override
protected void onResume()
{
super.onResume();
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(myReceiver, new IntentFilter(LocationUpdatesService.ACTION_BROADCAST));
GPSBeginRequestingUpdates();
}
#Override
protected void onPause()
{
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(myReceiver);
super.onPause();
}
private class GPSReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Location location = intent.getParcelableExtra(LocationUpdatesService.EXTRA_LOCATION);
if (location != null) {
Log.i(TAG, "\nonReceived New Location: " + GPSUtils.getLocationText(location));
GPSHeartbeat.instance(context.getApplicationContext()).SetLocation(location);
}
}
}
}
The Singleton. The SetLocation() does receive the correct location. It is only during my POST request that the APICommunicator is using the GPSHeartbeat's old location. Even though it was just updated.
How do I make sure I update to the correct location?
public class GPSHeartbeat extends Service {
private static String TAG = "GPSHeartbeat";
private static volatile GPSHeartbeat _instance;
private final WeakReference<Context> mContextRef;
private Boolean isRunning = false;
private int mInterval;
private Location mLocation;
private Handler mHandler;
private ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
private Future mLongRunningTaskFuture;
private Runnable mStatusChecker = new Runnable()
{
#Override
public void run()
{
try {
tick(); //this function can change value of mInterval.
}
finally {
if (isRunning()) {
// 100% guarantee that this always happens, even if your update method throws an exception
mHandler.postDelayed(mStatusChecker, mInterval);
}
}
}
};
private GPSHeartbeat(Context context)
{
mContextRef = new WeakReference<>(context.getApplicationContext());
}
public static GPSHeartbeat instance(Context context)
{
if (_instance == null) {
_instance = new GPSHeartbeat(context);
} else {
if (!context.equals(_instance.mContextRef.get())) {
_instance = null;
_instance = new GPSHeartbeat(context);
}
}
return _instance;
}
public void SetLocation(Location loc)
{
Log.i(TAG, "setLocation(): " + loc);
this.mLocation = loc;
}
public GPSHeartbeat setInterval(int interval)
{
this.mInterval = interval * 1000;
return this;
}
public void start()
{
if (isRunning()) return;
mHandler = new Handler();
mLongRunningTaskFuture = mExecutorService.submit(mStatusChecker);
mStatusChecker.run();
isRunning = true;
}
public void stop()
{
if (mHandler != null) {
mHandler.removeCallbacks(mStatusChecker);
}
if (mLongRunningTaskFuture != null) {
//kill the task:
try {
mLongRunningTaskFuture.cancel(true);
mLongRunningTaskFuture = null;
mHandler = null;
}
catch (Exception e) {
Log.e(TAG, "Unable to cancel task: " + e.getLocalizedMessage());
}
}
isRunning = false;
}
public Location currentLocation()
{
return mLocation;
}
public boolean isRunning()
{
return isRunning;
}
private void tick()
{
// Fire off the APICommuncator.Post() method
}
#Nullable
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
The APICommuncator
public class APICommuncator
{
private static String TAG = "APICommuncator";
private static volatile APICommuncator _instance;
private final WeakReference<Context> mContextRef;
private GPSHeartbeat _gpsHeartbeat;
private APICommuncator(Context context)
{
mContextRef = new WeakReference<>(context.getApplicationContext());
_gpsHeartbeat = GPSHeartbeat.instance(context.getApplicationContext());
}
public static APICommuncator i(Context context)
{
if (_instance == null) {
_instance = new APICommuncator(context);
} else {
if (!context.equals(_instance.mContextRef.get())) {
_instance = null;
_instance = new APICommuncator(context);
}
}
return _instance;
}
public void Post(){
// Do the background thing and grab
// getLocationNode() which gets the OLD location before it went to the background.
}
private JSONObject getLocationNode()
{
Location location = _gpsHeartbeat.currentLocation();
if (location == null) {
return null;
}
JSONObject node = null;
try {
node = new JSONObject();
node.put("Latitude", String.valueOf(location.getLatitude()));
node.put("Longitude", String.valueOf(location.getLongitude()));
node.put("HAccuracy", String.valueOf(location.getAccuracy()));
node.put("VAccuracy", String.valueOf(location.getAccuracy()));
node.put("Altitude", String.valueOf(location.getAltitude()));
node.put("Speed", String.valueOf(location.getSpeed() * 2.237));
node.put("Heading", String.valueOf(location.getBearing()));
node.put("Timestamp", String.valueOf((location.getTime() / 1000)));
}
catch (JSONException | NullPointerException e) {
e.printStackTrace();
}
return node;
}
}
In the Manifest:
<service
android:name=".gpsheartbeat.GPSHeartbeat"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".gpsheartbeat.LocationUpdatesService"
android:enabled="true"
android:exported="true"
android:foregroundServiceType="location" />
Actually I don't see that you are using foreground service. Not foreground service would be killed very soon after the application goes background. Plus communication with API should be in the scope of foreground service because activity could be killed by the system.
I am looking for a way to check and to listen to my internet connection but since the latest Android version doesn't support registering a broadcast in Manifest, I am looking for a way to implement something that works on all the Android versions. So far I couldn't find any solutions.
I tried adding a Broadcast intent filter into my Manifest file but that's not allowed in the more recent Android versions.
<receiver
android:name="utilities.NetworkStateChangeReceiver"
android:exported="true"
android:enabled="true"
android:label="NetworkConnection" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.STATE_CHANGE"/>
</intent-filter>
</receiver>
public class NetworkStateChangeReceiver extends BroadcastReceiver {
public static final String NETWORK_AVAILABLE_ACTION = "NetworkAvailable";
public static final String IS_NETWORK_AVAILABLE = "isNetworkAvailable";
#Override
public void onReceive(Context context, Intent intent) {
Intent networkStateIntent = new Intent(NETWORK_AVAILABLE_ACTION);
networkStateIntent.putExtra(IS_NETWORK_AVAILABLE, isConnectedToInternet(context));
LocalBroadcastManager.getInstance(context).sendBroadcast(networkStateIntent);
}
private boolean isConnectedToInternet(Context context) {
final ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
boolean isMobile = false, isWifi = false;
NetworkInfo[] infoAvailableNetworks = cm.getAllNetworkInfo();
if (infoAvailableNetworks != null) {
for (NetworkInfo network : infoAvailableNetworks) {
if (network.getType() == ConnectivityManager.TYPE_WIFI) {
if (network.isConnected() && network.isAvailable())
isWifi = true;
}
if (network.getType() == ConnectivityManager.TYPE_MOBILE) {
if (network.isConnected() && network.isAvailable())
isMobile = true;
}
}
}
return isMobile || isWifi;
}
}
My receiver is not able to receive a broadcast
I'm using pretty much the same logic with IntentFilter and it works for me pretty good without registering it in the Manifest file.
Interface:
public interface IReceiverStateChange {
void register(BroadcastReceiver broadcastReceiver);
void unregister(BroadcastReceiver broadcastReceiver);
}
Implementation:
public class NetworkReceiverStateChange implements IReceiverStateChange {
private Context mContext;
private Boolean mIsRegistered = false;
public NetworkReceiverStateChange(Context context) {
mContext = context;
}
#Override
public void register(BroadcastReceiver broadcastReceiver) {
if (!mIsRegistered) {
IntentFilter netWorkIntentFilter = new
IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
mContext.registerReceiver(broadcastReceiver, netWorkIntentFilter);
mIsRegistered = true;
}
}
#Override
public void unregister(BroadcastReceiver broadcastReceiver) {
if (mIsRegistered) {
mContext.unregisterReceiver(broadcastReceiver);
mIsRegistered = false;
}
}
}
Register in the desired activity:
if (mNetworkStateChange == null) {
mNetworkStateChange = new NetworkReceiverStateChange(this);
}
mNetworkStateChange.register(mNetworkBroadcastReceiver);
Unregister in onDestroy:
if (mNetworkStateChange != null) {
mNetworkStateChange.unregister(mNetworkBroadcastReceiver);
}
The BroadcastReceiver Obj:
//The CONNECTIVITY_ACTION broadcast seems to be sticky on some devices (even
though the documentation implies that it is not).
// This means that when you register the receiver it will immediately call
onReceive() with the most recently sent broadcast.
private final BroadcastReceiver mNetworkBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action != null && action.matches("android.net.conn.CONNECTIVITY_CHANGE")) {
<DO SOMETHING>
}
}
};
Hope it helps :)
If you want to check your internet connection all of your activities you can follow below code :-
NetworkSchedulerService.java
public class NetworkSchedulerService extends JobService implements
ConnectivityReceiver.ConnectivityReceiverListener {
private static final String TAG = NetworkSchedulerService.class.getSimpleName();
private ConnectivityReceiver mConnectivityReceiver;
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "Service created");
prefManager = PrefManager.getInstance(this);
mConnectivityReceiver = new ConnectivityReceiver(this);
}
/**
* When the app's NetworkConnectionActivity is created, it starts this service. This is so that the
* activity and this service can communicate back and forth. See "setUiCallback()"
*/
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return START_NOT_STICKY;
}
#Override
public boolean onStartJob(JobParameters params) {
Log.i(TAG, "onStartJob" + mConnectivityReceiver);
registerReceiver(mConnectivityReceiver, new IntentFilter(CONNECTIVITY_ACTION));
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
Log.i(TAG, "onStopJob");
unregisterReceiver(mConnectivityReceiver);
return true;
}
#Override
public void onNetworkConnectionChanged(boolean isConnected) {
if(isConnected){
Toast.makeText(this,"connected to internet",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this,"no internet connection",Toast.LENGTH_SHORT).show();
}
}
}
In manifest file
<service
android:name=".NetworkSchedulerService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE"/>```
create a Application class
class MyApplication extends Application {
override fun onCreate() {
super.onCreate()
scheduleJob()
}
override fun onStop() {
super.onStop()
// A service can be "started" and/or "bound". In this case, it's "started" by this Activity
// and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
// to stopService() won't prevent scheduled jobs to be processed. However, failing
// to call stopService() would keep it alive indefinitely.
stopService(Intent(this, NetworkSchedulerService::class.java))
}
override fun onStart(){
val startServiceIntent = Intent(this, NetworkSchedulerService::class.java)
startService(startServiceIntent)
}
private fun scheduleJob() {
val myJob = JobInfo.Builder(0, ComponentName(this, NetworkSchedulerService::class.java))
.setRequiresCharging(true)
.setMinimumLatency(1000)
.setOverrideDeadline(2000)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.build()
val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
jobScheduler.schedule(myJob)
}
}
define application class in manifest file
BroadcastReceiver class ->
public class ConnectivityReceiver extends BroadcastReceiver {
private ConnectivityReceiverListener mConnectivityReceiverListener;
ConnectivityReceiver(ConnectivityReceiverListener listener) {
mConnectivityReceiverListener = listener;
}
#Override
public void onReceive(Context context, Intent intent) {
mConnectivityReceiverListener.onNetworkConnectionChanged(isConnected(context));
}
public static boolean isConnected(Context context) {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}
public interface ConnectivityReceiverListener {
void onNetworkConnectionChanged(boolean isConnected);
}
}
**onNetworkConnectionChanged will notify when internet is connected or not (NetworkSchedulerService.java)
Don't define BroadCastReceiver in manifest file. make sure to provide internect permission , CHANGE_NETWORK_STATE,ACCESS_NETWORK_STATE
**
I hope this will help you. Let me know if there is any problem. Happy Coding :-)
I am trying to update the UI according to change of a variable in BroadcastReceiver. Thus, I need to call a method (to get the variable I mentioned) of a class which extends BroadcastReceiver in MainActivity depending on but I cannot get the true return value in any way.
The class which extends BroadcastReceiver is this:
public class ProviderChangeReceiver extends BroadcastReceiver {
private static boolean isProviderActive;
#Override
public void onReceive(Context context, Intent intent) {
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.v("-> ", "GPS + NETWORK");
isProviderActive = true;
}
else if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && !lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.v("-> ", "GPS");
isProviderActive = true;
}
else if (lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) && !lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Log.v("-> ", "NETWORK");
isProviderActive = true;
}
else
{
Log.v("-> ", "DISCONNECT");
isProviderActive = false;
}
}
public static boolean isProviderActive(){
return isProviderActive;
}
}
I need to get true value of isProviderActive to use in this part of MainActivity:
...
private class ProviderChangeReceiver_updateUI extends ProviderChangeReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
MapsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("-A", ""+ isProviderActive());
if (isProviderActive())
originButton.setVisibility(View.VISIBLE);
else
originButton.setVisibility(View.INVISIBLE);
}
});
}
}
I know that indicating isProviderActive as static is not a good approach but I just want to observe its changes. As you guess, I got nonsensical return values all the time. To values of boolean isProviderActive without problem, what do you advise?
Edit: My temporary solution to update UI according to changes in BroadcastReceiver.
Forget about creating a separate class for ProviderChangeReceiver. Instead of the code segment above, following segment should be added in MainActivity. Also, it goes without saying that there is the initialization of ProviderChangeReceiver in onCreate().
...
private class ProviderChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
MapsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("COUNT: ", "" + count++);
if (isLocationProviderActive()) {
originButton.getBackground().setAlpha(220);
originButton.setEnabled(true);
//marker.setVisible(true);
}
else {
originButton.getBackground().setAlpha(77);
originButton.setEnabled(false);
marker.setVisible(false);
}
}
});
}
}
private boolean isLocationProviderActive(){
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
return true;
return false;
}
Of course then register the receiver in onCreate() as well:
registerReceiver(pcr, new IntentFilter("android.location.PROVIDERS_CHANGED"));
The reason that every time isProvidrActive changed the whole activity got regenerated is because I sent the intent using context.startActivity(i) but rather this time we send the intent using contect.sendBroadcast(i) to the ProviderChangeReceiver_updateUI inner class which update only desired part of the UI. So below is the new code.
private static boolean isProviderActive;
#Override
public void onReceive(Context context, Intent intent) {
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.v("-> ", "GPS + NETWORK");
isProviderActive = true;
}
else if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && !lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.v("-> ", "GPS");
isProviderActive = true;
}
else if (lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) && !lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Log.v("-> ", "NETWORK");
isProviderActive = true;
}
else
{
Log.v("-> ", "DISCONNECT");
isProviderActive = false;
}
//Send value of isProviderActive to ProviderChangeReceiver_updateUI
Intent i = new Intent(context, ProviderChangeReceiver_updateUI.class);
i.putExtra("isProvidrActv", isProviderActive);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.sendBroadcast(i);
}
Edit your manifest file to enable the inner class ProviderChangeReceiver_updateUI to listen for broadcast sent by our broadcastReciever, add the following entry to manifest
<receiver android:name="<package-name>.MainActivity$ProviderChangeReceiver_updateUI"
android:enabled="true" >
<intent-filter>
</intent-filter>
</receiver>
the $ sign indicates inner class. No need to add intent-filters unless required.
And in your ProviderChangeReceiver_updateUI class in the onReceive() method get the value of isProviderActive
...
//changed the identifiers from private to public static and the class extends //BroadcastReceiver
public static class ProviderChangeReceiver_updateUI extends BroadcastReceiver {
//Empty constructor to prevent exception can't instantiate no empty constructor
public ProviderChangeReceiver_updateUI(){
}
//Removed the final keyword from handler
private Handler handler; // Handler used to execute code on the UI thread
public ProviderChangeReceiver_updateUI(Handler handler) {
this.handler = handler;
}
#Override
public void onReceive(final Context context, final Intent intent) {
boolean isProvidrActv = intent.getBooleanExtra("isProvidrActv", false);
//mapsActivity is a global static object of the class MapsActivity<br/>
//instantiate it the onCreate() method of mainactivity for ex:<br/>
/*public class MapsActivity extends Activity{<br/>
static MapsActivity mapsActivity;
#Override
protected void onCreate(Bundle savedInstancestate){
ma = new MapsActivity();
}*/
mapsActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (isProvidrActv)
originButton.setVisibility(View.VISIBLE);
else
originButton.setVisibility(View.INVISIBLE);
}
});
}
}
I think a nice way to handle something like this is with an eventbus.
Take a look at Squares Otto library.
In your broadcast receiver you would publish the change event and then in your activity you would subscribe to the event and update the ui.
Based on the context of your question, I think you would be able to avoid the broadcast receiver entirely, since I suspect you have something watching your provider and then broadcasting the event.
Update: (based on comments)
I think the way this would work would be something like this
In the code that detects the change in location provider:
if (bothProvidersAreStopped()) {
bus.publish(new BothProvidersStoppedEvent());
} else if (onlyNetworkProviderIsStopped() {
bus.publish(new NetworkProviderStoppedEvent());
} else if (onlyGpsProviderIsStopped() {
bus.publish(new GpsProviderStoppedEvent());
}
in your activity
#Subscribe public void onBothProvidersStopped(BothProvidersStopped event) {
// handle case were both providers just stopped
}
#Subscribe public void onNetworkProvidersStopped(BothProvidersStopped event) {
// handle case were network provider just stopped
}
#Subscribe public void onGpsProvidersStopped(BothProvidersStopped event) {
// handle case were gps provider just stopped
}
I already have this code which listens to connectivity change -
public class NetworkStateReceiver extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent)
{
Log.d("app","Network connectivity change");
if(intent.getExtras() != null)
{
NetworkInfo ni = (NetworkInfo) intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
if(ni != null && ni.getState() == NetworkInfo.State.CONNECTED)
{
Log.i("app", "Network " + ni.getTypeName() + " connected");
}
}
if(intent.getExtras().getBoolean(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE))
{
Log.d("app", "There's no network connectivity");
}
}
}
And I check Internet connectivity using this code - Internet Check
But the problem is that if network suddenly loses internet connection without any connectivity change, this code is useless. Is there any way to create Broadcast Receiver listener for Internet connectivity change? I have a web app and sudden Internet connectivity changes can cause problems.
Try this
public class NetworkUtil {
public static final int TYPE_WIFI = 1;
public static final int TYPE_MOBILE = 2;
public static final int TYPE_NOT_CONNECTED = 0;
public static final int NETWORK_STATUS_NOT_CONNECTED = 0;
public static final int NETWORK_STATUS_WIFI = 1;
public static final int NETWORK_STATUS_MOBILE = 2;
public static int getConnectivityStatus(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (null != activeNetwork) {
if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
return TYPE_WIFI;
if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
return TYPE_MOBILE;
}
return TYPE_NOT_CONNECTED;
}
public static int getConnectivityStatusString(Context context) {
int conn = NetworkUtil.getConnectivityStatus(context);
int status = 0;
if (conn == NetworkUtil.TYPE_WIFI) {
status = NETWORK_STATUS_WIFI;
} else if (conn == NetworkUtil.TYPE_MOBILE) {
status = NETWORK_STATUS_MOBILE;
} else if (conn == NetworkUtil.TYPE_NOT_CONNECTED) {
status = NETWORK_STATUS_NOT_CONNECTED;
}
return status;
}
}
And for the BroadcastReceiver
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
int status = NetworkUtil.getConnectivityStatusString(context);
Log.e("Sulod sa network reciever", "Sulod sa network reciever");
if ("android.net.conn.CONNECTIVITY_CHANGE".equals(intent.getAction())) {
if (status == NetworkUtil.NETWORK_STATUS_NOT_CONNECTED) {
new ForceExitPause(context).execute();
} else {
new ResumeForceExitPause(context).execute();
}
}
}
}
Don't forget to put this into your AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<receiver
android:name="NetworkChangeReceiver"
android:label="NetworkChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
Hope this will help you Cheers!
ConnectivityAction is deprecated in api 28+. Instead you can use registerDefaultNetworkCallback as long as you support api 24+.
In Kotlin:
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
connectivityManager?.let {
it.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
//take action when network connection is gained
}
override fun onLost(network: Network?) {
//take action when network connection is lost
}
})
}
Here's the Java code using registerDefaultNetworkCallback (and registerNetworkCallback for API < 24):
ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
// network available
}
#Override
public void onLost(Network network) {
// network unavailable
}
};
ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.registerDefaultNetworkCallback(networkCallback);
} else {
NetworkRequest request = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
connectivityManager.registerNetworkCallback(request, networkCallback);
}
Update:
Apps targeting Android 7.0 (API level 24) and higher do not receive
CONNECTIVITY_ACTION broadcasts if they declare the broadcast receiver
in their manifest. Apps will still receive CONNECTIVITY_ACTION
broadcasts if they register their BroadcastReceiver with
Context.registerReceiver() and that context is still valid.
You need to register the receiver via registerReceiver() method:
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
mCtx.registerReceiver(new NetworkBroadcastReceiver(), intentFilter);
This should work:
public class ConnectivityChangeActivity extends Activity {
private BroadcastReceiver networkChangeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("app","Network connectivity change");
}
};
#Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkChangeReceiver, intentFilter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(networkChangeReceiver);
}
}
I used this method as a connection listener. Working for Lolipop+, Android JAVA language.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest networkRequest = new NetworkRequest.Builder().build();
connectivityManager.registerNetworkCallback(networkRequest, new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.i("Tag", "active connection");
}
#Override
public void onLost(Network network) {
super.onLost(network);
Log.i("Tag", "losing active connection");
isNetworkConnected();
}
});
}
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (!(cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected())) {
//Do something
return false;
}
return true;
}
And also add this permission in your Android Manifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Hello from the year 2022.
In my custom view model I observe network status changes like this:
public class MyViewModel extends AndroidViewModel {
private final MutableLiveData<Boolean> mConnected = new MutableLiveData<>();
public MyViewModel(Application app) {
super(app);
ConnectivityManager manager = (ConnectivityManager)app.getSystemService(Context.CONNECTIVITY_SERVICE);
if (manager == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
mConnected.setValue(true);
return;
}
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
manager.registerNetworkCallback(networkRequest, new ConnectivityManager.NetworkCallback() {
Set<Network> availableNetworks = new HashSet<>();
public void onAvailable(#NonNull Network network) {
availableNetworks.add(network);
mConnected.postValue(!availableNetworks.isEmpty());
}
public void onLost(#NonNull Network network) {
availableNetworks.remove(network);
mConnected.postValue(!availableNetworks.isEmpty());
}
public void onUnavailable() {
availableNetworks.clear();
mConnected.postValue(!availableNetworks.isEmpty());
}
});
}
#NonNull
public MutableLiveData<Boolean> getConnected() {
return mConnected;
}
}
And then in my Activity or Fragment I can change the UI by observing:
#Override
protected void onCreate(Bundle savedInstanceState) {
MyViewModel vm = new ViewModelProvider(this).get(MyViewModel.class);
vm.getConnected().observe(this, connected -> {
// TODO change GUI depending on the connected value
});
}
first add dependency in your code as implementation 'com.treebo:internetavailabilitychecker:1.0.4'
implements your class with InternetConnectivityListener.
public class MainActivity extends AppCompatActivity implements InternetConnectivityListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InternetAvailabilityChecker.init(this);
mInternetAvailabilityChecker = InternetAvailabilityChecker.getInstance();
mInternetAvailabilityChecker.addInternetConnectivityListener(this);
}
#Override
public void onInternetConnectivityChanged(boolean isConnected) {
if (isConnected) {
alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle(" internet is connected or not");
alertDialog.setMessage("connected");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
else {
alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("internet is connected or not");
alertDialog.setMessage("not connected");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
}
}
I have noticed that no one mentioned WorkManger solution which is better and support most of android devices.
You should have a Worker with network constraint AND it will fired only if network available, i.e:
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
val worker = OneTimeWorkRequestBuilder<MyWorker>().setConstraints(constraints).build()
And in worker you do whatever you want once connection back, you may fire the worker periodically .
i.e:
inside dowork() callback:
notifierLiveData.postValue(info)
According to the official docs:
Define network request
private val networkRequest = NetworkRequest.Builder().apply {
// To check wifi and cellular networks for internet availability
addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Capabilities can be verified starting Android 6.0.
// For a network with NET_CAPABILITY_INTERNET,
// it means that Internet connectivity was successfully detected
addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Indicates that this network is available for use by apps,
// and not a network that is being kept up in the background
// to facilitate fast network switching.
addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND)
}
}.build()
Configure a network callback
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
private val networks = mutableListOf<Network>()
override fun onAvailable(network: Network) {
super.onAvailable(network)
networks.add(network)
Log.d("Has network --->", networks.any().toString())
}
override fun onLost(network: Network) {
super.onLost(network)
networks.remove(network)
Log.d("Has network --->", networks.any().toString())
}
}
Register for network updates
val connectivityService =
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
connectivityService.registerNetworkCallback(networkRequest, networkCallback)
ref https://developer.android.com/training/monitoring-device-state/connectivity-status-type
To specify the transport type of the network, such as Wi-Fi or
cellular connection, and the currently connected network's
capabilities, such as internet connection, you must configure a
network request.
Declare a NetworkRequest that describes your app’s network connection
needs. The following code creates a request for a network that is
connected to the internet and uses either a Wi-Fi or cellular
connection for the transport type.
add this in onCreate
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
Configure a network callback When you register the NetworkRequest with
the ConnectivityManager, you must implement a NetworkCallback to
receive notifications about changes in the connection status and
network capabilities.
The most commonly implemented functions in the NetworkCallback include
the following:
onAvailable() indicates that the device is connected to a new network
that satisfies the capabilities and transport type requirements
specified in the NetworkRequest. onLost() indicates that the device
has lost connection to the network. onCapabilitiesChanged() indicates
that the capabilities of the network have changed. The
NetworkCapabilities object provides information about the current
capabilities of the network.
add listener
private ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(#NonNull Network network) {
super.onAvailable(network);
}
#Override
public void onLost(#NonNull Network network) {
super.onLost(network);
}
#Override
public void onCapabilitiesChanged(#NonNull Network network, #NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
final boolean unmetered = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
}};
Register for network updates After you declare the NetworkRequest and
NetworkCallback, use the requestNetwork() or registerNetworkCallback()
functions to search for a network to connect from the device that
satisfies the NetworkRequest. The status is then reported to the
NetworkCallback.
Register in onCreate
ConnectivityManager connectivityManager =
(ConnectivityManager) getSystemService(ConnectivityManager.class);
connectivityManager.requestNetwork(networkRequest, networkCallback);
implementation 'com.treebo:internetavailabilitychecker:1.0.1'
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
InternetAvailabilityChecker.init(this);
}
#Override
public void onLowMemory() {
super.onLowMemory();
InternetAvailabilityChecker.getInstance().removeAllInternetConnectivityChangeListeners();
}
}