Почему LocationCallback не запускается в CallbackToFutureAdapter?

Что мне нужно сделать: мое приложение должно запрашивать текущее местоположение пользователя, повторяя каждые 15 минут, также в фоновом режиме и даже когда приложение завершено.

Что я сделал: я использую FusedLocationProviderAPI, вызываемый в периодическом WorkManager, расширяя ListenableWorker, поскольку API асинхронный. Каждый раз, когда система предоставляет новое обновление местоположения (максимум каждые пятнадцать минут), вызывается LocationCallback.

Поскольку ResolvableFuture, похоже, не рекомендуется использовать в методе startWork ListenableWorker, я использую CallbackToFutureAdapter. В этом адаптере я инициализирую LocationCallback и вызываю doWork-Method, который включает всю логику для запроса информации.

Моя проблема: При активном экране все работает нормально. Но как только приложение запускается в фоновом режиме или завершается, LocationCallback не вызывается. (последний журнал: «Ожидание обратного вызова»). Обратите внимание, что я удалил большие фрагменты кода ниже (например, обработку исключений и детали).

Вот мой код в MyWorker extends ListenableWorker startWork-Method:

public ListenableFuture<Result> startWork() {
        return CallbackToFutureAdapter.getFuture(completer -> {

            mLocationCallback = new LocationCallback() {

                @Override
                public void onLocationResult(LocationResult locationResult) {
                    super.onLocationResult(locationResult);

                   // Storing data to different repositories.

                    completer.set(Result.success());
                }

            };
            doWork();

            return "startSomeAsyncStuff";
        });
    } 

Выполнять работу():

public Result doWork() {

               mFusedLocationClient = LocationServices.getFusedLocationProviderClient(mContext);
                mSettingsClient = LocationServices.getSettingsClient(mContext);
                createLocationCallback();
                createLocationRequest();
                buildLocationSettingsRequest();

               startLocationUpdates();

        return Result.success();
    }

startLocationUpdates ():

 private void startLocationUpdates() {
        // Begin by checking if the device has the necessary location settings.
        mSettingsClient.checkLocationSettings(mLocationSettingsRequest)
                .addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
                    @Override
                    public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
                        Log.i(TAG, "All location settings are satisfied.");
                        mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper());
                   Log.i(TAG, "Location updated requested - Waiting for Callback");

                    }
                })

Связанные сообщения: Как вернуть ListenableFuture ‹ Результат ›с менеджером работы 2.0? и WorkManager: ResolvableFuture можно вызывать только из одного префикса группы библиотек


person d-reic    schedule 17.04.2020    source источник


Ответы (1)


Итак, после нескольких часов проб и ошибок вот решение, которое наконец-то сработало для меня:

Уловка состоит в том, чтобы добавить Foreground-Service, который гарантирует, что работник не будет отменен, пока из системы не поступит новое Location-Update. Однако вы не можете избежать отображения Уведомления в течение этого периода времени. Я также переместил LocationCallback в doWork-Method непосредственно перед запросом обновлений местоположения (поскольку вам нужно передать обратный вызов этому методу).

Это решение основано на https://developer.android.com/topic/libraries/architecture/workmanager/advanced/long-running, на который я должен был взглянуть вначале, чтобы избавить меня от разочарования;)

Вот метод startWork ():

 public ListenableFuture<Result> startWork() {
        return CallbackToFutureAdapter.getFuture(completer -> {
            setForegroundAsync(createForegroundInfo());

            doWork(completer);

            // This value is used only for debug purposes: it will be used
            // in toString() of returned future or error cases.
            return "Location Worker";
        });
    }
person d-reic    schedule 27.04.2020