Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to retrieve the current geolocation synchronously?

Due to the way our app works, I need to synchronously get the users current location. Our current implementation uses the com.google.android.gms.location.LocationListener to receive location updates. Problem is, I need to update the location server-side before attempting my first call, otherwise the user gets faulty data.

LocationServices.FusedLocationApi.getLastLocation() isn't suited for this, because a) it always seems to return null (for whatever reason) and b) we already save the users last known location server-side, so retrieving the last known location and sending it to the servers is redundant.

pseudocode

//this is the first call I need to make
webservice.appStart(AppStartBody body);
//then I want to retrieve the current location and send it to the server
webservice.setGeoLocation(getCurrentLocation());
//finally, I retrieve the items on the server based on the location
webservice.getListItems();

Waiting for the first location update event is a possibility that I want to avoid, because I don't know, how soon it will fire and I might have to keep my users in a loading screen for ages and in turn lose them, because nobody likes waiting.

like image 977
TormundThunderfist Avatar asked Oct 24 '16 13:10

TormundThunderfist


People also ask

Which function is used to get the current position using Geolocation API?

The Geolocation. getCurrentPosition() method is used to get the current position of the device.

How do I get Geolocation API?

The Geolocation API is accessed via a call to navigator. geolocation ; this will cause the user's browser to ask them for permission to access their location data. If they accept, then the browser will use the best available functionality on the device to access this information (for example, GPS).

How do I find the location of a website user?

One of the useful ways of getting your user location is by the use of IP address lookup although it may not be entirely free depending the API. Some very good APIs for this operation are http://ip-api.com/, https://ipinfo.io, geoip-db.com and many others.

Which object is used for Geolocation API?

The Geolocation API is available through the navigator. geolocation object.


1 Answers

I was able to get around this by placing the process of retrieving the location inside an Rx observable, specifically Single. The Single object's blockingGet method is called to retrieve the location synchronously. It is then placed inside a try catch block to perform retries since the location is not always available during the first try.

(I know this is an old question, but I'm gonna post an answer anyway so that I can share the way how I did it. Sorry for using Kotlin and RxJava! But I think everyone would get the gist of my idea and be able to implement it the way they like. I am also using the latest Google Location API.)

// Use an executor to prevent blocking the thread where 
// this method will be called. Also, DO NOT call this on 
// the main thread!!!
fun tryRetrieveLocationSync(flc: FusedLocationProviderClient,
          executor: Executor, numOfRetries: Int = 3, 
          retryWaitTime: Long = 500): Location {

  var location: Location
  var i = 1

  while (true) {
    try {
      // Place the method call inside a try catch block
      // because `Single#blockingGet` will throw any exception
      // that was provided to the `Emitter#onError` as an argument.

      location = retrieveLocationSync(flc, executor)
    } catch (e: NoLocationDataException) {
      if (i <= numOfRetries) {
        // The value from the `FusedLocationProviderClient#lastLocation` 
        // task usually becomes available after less than second (tried
        // and tested!!), but it's really up to you.

        SystemClock.sleep(retryWaitTime * i)
        i++
      } else {
        throw e // Give up once all the retries have been used.
      }
    } catch (e: Exception) {
      // Rethrow anything else that was thrown from 
      // the `Single#blockingGet`.

      throw e
    }
  }

  return location
}

private fun retrieveLocationSync(flc: FusedLocationProviderClient, 
          executor: Executor): Location {

  return Single.create<Location> { emitter ->
    val task = flc.lastLocation
    task.addOnCompleteListener(executor, OnCompleteListener { // it ->
      if (it.isSuccessful) {
        if (it.result != null) {
          emitter.onSuccess(it.result)
        } else {
          // There is no location data available probably because
          // the location services has just been enabled, the device
          // has just been turned on, or no other applications has 
          // requested the device's location.
          emitter.onError(NoLocationDataException())
        }
      } else {
        // I haven't encountered any exception here but this is
        // just to make sure everything's catchable.
        emitter.onError(it.exception ?: RuntimeException())
      }
    })
  }.blockingGet()
}
like image 115
bmdelacruz Avatar answered Oct 12 '22 23:10

bmdelacruz