0

I want to know whenever user turn his gps off. I want to get informed about that action in different activities. I made Broadcast Receiver to listen for GPS state change. But almost always when i turn off GPS, my updateValue function get fired twice. How to get notified one time, when user turn his gps off? What i did wrong? Below is my code.

class GpsStatusReceiver : BroadcastReceiver() {
var observableGpsState: ObservableGpsState? = null

override fun onReceive(context: Context?, intent: Intent?) {
    val locationManager = context?.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
        //GPS Turned on,OK..
    } else {
        if (observableGpsState == null)
            observableGpsState = ObservableGpsState.getInstance()
        observableGpsState?.updateValue(GPS_STATUS_TURNED_OFF)
    }
}

companion object {
    val GPS_STATUS_TURNED_OFF = "GPS_TURNED_OFF"
}}

My Observable

class ObservableGpsState: Observable(){

fun updateValue(data: Any) {
    synchronized(this) {
        setChanged()
        notifyObservers(data)
    }
}
companion object {
    private val instance = ObservableGpsState()
    fun getInstance(): ObservableGpsState {
        return instance
    }
}}

And (what I guess) is important from my Activity:

protected lateinit var observer: Observable

private fun registerGpsObserver(){
    observer = ObservableGpsState.getInstance()
    observer.addObserver(this)
}
private fun unregisterGpsObserver(){
    observer.deleteObserver(this)
}

override fun update(o: Observable?, arg: Any?) {
    MyApplication.get(baseContext).enableGpsDialog(this)
}
Karol
  • 58
  • 8

3 Answers3

1

I would assume that this issue arises only on some devices (though I am not 100% sure about it, but it is the case when listening to network changes via a BroadcastReceiver so it would make sense).

Anyway the simplest solution would be to Make an enum which holds the current State of your GPS. Only if the State changes notify the Observer. This way the onReceive could be called 1000 times but your Observer gets notified only once.

Rene Ferrari
  • 4,096
  • 3
  • 22
  • 28
0

I solved with :

 BroadcastReceiver gpsSwitchStateReceiver = new BroadcastReceiver() {
    //here you can check your current state when instanciate it.
        boolean oldLocationEnabled = isLocationSystemEnabled();

        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                String action;
                if (intent != null && (action = intent.getAction()) != null && action.matches(LocationManager.PROVIDERS_CHANGED_ACTION)) {
                    boolean locationEnabled = isLocationSystemEnabled();
//this validation ensures that it is executed only once (since the receiver is executed in the UIThread) 
                    if (oldLocationEnabled != locationEnabled) {
                        if (locationEnabled) {
                        //your code here 
                        } else {
                        //when dont have location here
                        }
                    }
                    oldLocationEnabled = locationEnabled;
                }
            } catch (Exception ignored) {}
        }
    };

public boolean isLocationSystemEnabled() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        LocationManager locationManager = (LocationManager) ApplicationLoader.appContext.getSystemService(Context.LOCATION_SERVICE);
        boolean         isGPSEnabled    = false;
        boolean         isNetEnabled    = false;
        if (locationManager != null) {
            isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            isNetEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        }
        return isGPSEnabled || isNetEnabled;
    } else {
        String allowedLocationProviders = Settings.System.getString(ApplicationLoader.appContext.getContentResolver(), Settings.System.LOCATION_PROVIDERS_ALLOWED);
        if (allowedLocationProviders == null) {
            allowedLocationProviders = "";
        }
        return allowedLocationProviders.contains(LocationManager.GPS_PROVIDER);
    }
}
Arthur Melo
  • 454
  • 5
  • 13
0

There are multiple location providers in Android. Therefore, the event you are listening to corresponds to provider changes, and not to location activation. See https://stackoverflow.com/a/6775456/13941008.

Use LocationManager.MODE_CHANGED_ACTION instead and retrieve the current location activation status using LocationManager.EXTRA_LOCATION_ENABLED directly from the Intent argument. Example:

val locationListener = object : BroadcastReceiver() {
   override fun onReceive(context: Context?, intent: Intent) {
      when(val action = intent.action){
         LocationManager.MODE_CHANGED_ACTION -> {
            val locationState = intent.getBooleanExtra(
               LocationManager.EXTRA_LOCATION_ENABLED,
               false
            )
          // Do something using locationState variable
          } else -> {
             Log.d(TAG, "Unsupported action received $action")
          }
      }
   }
}

val intentFilter = IntentFilter(LocationManager.MODE_CHANGED_ACTION)
context.registerReceiver(locationListener, intentFilter)

Finally, do not forget to unregister the receiver when it is no longer needed. Example:

context.unregisterReceiver(locationListener)
Josué RL
  • 1
  • 1
  • 4