How can I perform android location checks in intervals?

Viewed 49

I have need to retrieve android device coordinates from android application and send these coordinates to sever even when the application is stopped and/or the device is asleep. I need to do this in fixed time intervals.

I clearly understand that this is complex solution, but could you please mention key aspects, that are needed to solve this problem? I need a direction to choose in the process of developing the application.

I have made extensive research on the web, there are many solutions but some of them seem to be several years old and others tend to solve particular problems in different ways. Its Impossible to try them all and from all this information compose the solution that will answer my needs and will be optimal and stable solution.

Thank you

1 Answers

I had the same problem and this solution worked for me:

Define a worker like below:

class SendLocationWorker(
  context: Context,
  workerParams: WorkerParameters
) : Worker(context, workerParams) {
  private var retrofit: Retrofit? = null
  private var locationApi: MyApi? = null
  private val userLocationDao = AppDatabase.getInstance(applicationContext)
      .userLocationDao()

  override fun doWork(): Result {
    return try {
      if (retrofit == null) {
        retrofit = MasterRetrofit().initRetrofit(Constants.MAIN_URL)
      }
      if (locationApi == null) {
        locationApi = retrofit!!.create(MyApi::class.java)
      }
      callApi()
      Result.success()
    } catch (ex: Exception) {
      Result.failure()
    }
  }

  @SuppressLint("CheckResult")
  private fun callApi() {
    val locations = getUserLocations()
    if (locations.isNotEmpty()) {
      val request = InsertLocationUserRequest()
      request.saveTrackings = locations

      locationApi!!.SaveTracking(request)
          .subscribeOn(Schedulers.io())
          .observeOn(AndroidSchedulers.mainThread())
          .map(SuccessMapper<Response<InsertLocationUserResponse>>())
          .subscribe(
              { response ->
                if (response.body()!!.success) {
                  Observable.fromIterable(locations)
                      .forEach { location -> location.isSync = true }
                  userLocationDao.update(locations)
                }
              },
              { throwable ->

              },
              {
              }
          )
    }
  }

  private fun getUserLocations(): List<UserLocation> {
    return userLocationDao.findAll("isSync", "0")
  }
}

Also, you need to define a method in MasterActivity or MasterPresenter like this:

  @Override public void sendStoredLocationToServer() {
    Constraints myConstraints = new Constraints.Builder()
        .setRequiresBatteryNotLow(true)
        .build();

    PeriodicWorkRequest sendLocationWorkerRequest =
        new PeriodicWorkRequest.Builder(SendLocationWorker.class, 10000, TimeUnit.MILLISECONDS)
            .setConstraints(myConstraints)
            .build();

    WorkManager.getInstance().enqueueUniquePeriodicWork("sendLocationWorker",
        ExistingPeriodicWorkPolicy.REPLACE,
        sendLocationWorkerRequest);
  }

Then you can call your worker in your MasterActivity or MasterPresenter everywhere you want like this:

sendStoredLocationToServer();

This worker will save your locations in the database and send them if it is possible and mark all send items as true (using isSyns flag).

This idea worked well for me.

Related