Как можно обрабатывать обновления местоположения от FusedLocationProviderClient с помощью диспетчера работ?

Во-первых, я полный Android-новичок. Некоторое время искали решения, но пока не нашли никаких полезных советов в правильном направлении. Как правило, это может быть вызвано характером самой проблемы, поскольку она является нишевой.

Рабочий код, представленный ниже, основан на лаборатории кода на странице https://codelabs.developers.google.com/codelabs/realtime-asset-tracking.

Однако мне было интересно, поскольку сейчас он упоминался в нескольких ресурсах как предпочтительный способ, как бы вы сделали что-то подобное на основе Android Work Manager вместо службы с постоянным уведомлением?

public class TrackerService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        requestLocationUpdates();
    }

    private void requestLocationUpdates() {
        LocationRequest request = new LocationRequest();
        request.setInterval(5 * 60 * 1000);
        request.setFastestInterval(30 * 1000);
        request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        FusedLocationProviderClient client = LocationServices.getFusedLocationProviderClient(this);
        int permission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
        if (permission == PackageManager.PERMISSION_GRANTED) {
            client.requestLocationUpdates(request, new LocationCallback() {
                @Override
                public void onLocationResult(LocationResult locationResult) {
                    Location location = locationResult.getLastLocation();
                    if (location != null) {
                        Log.d(TAG, "location update " + location);
                    }
                }
            }, null);
        }
    }
}

По моему опыту работы с веб-проектами, приведенный выше код устанавливает «слушателя» на основе FusedLocationProviderClient. Как только появится новое обновление местоположения, он вызовет onLocationResult с соответствующим результатом местоположения.

Что я узнал о диспетчере работ, так это то, что вы можете настроить сотрудника с диспетчером работ для doWork() один раз или периодически. Практически как работа cron ...

Чего я не понимаю, если в фоновом режиме нет работающей службы, где будет инициирован Worker и запрос обновлений местоположения? И как они будут работать вместе?


comment
Давайте проясним, вы инициируете свой запрос на обновления местоположения в своем классе, который является наследником класса Worker, и вы запустите свою собственную функцию doWork. Посмотрите на этот пример - codelabs.developers.google.com/codelabs/android- workmanager / № 3   -  person Vadim Eksler    schedule 02.12.2018
comment
Спасибо @VadimEksler - Этот код войдет в мою активность по умолчанию? Если бы я периодически запускал воркера, разве он не регистрировал бы несколько обратных вызовов для обновления местоположения?   -  person individual8    schedule 02.12.2018
comment
1) Отдельный класс MyLocationWorker, расширяющий Worker. И вы запускаете это как PeriodicWorkRequest myWorkRequest = new PeriodicWorkRequest.Builder(MyLocationWorker.class, 30, TimeUnit.MINUTES) .build(); 2) Вам нужно удалить обратный вызов, когда вы получите результат своего местоположения.   -  person Vadim Eksler    schedule 02.12.2018


Ответы (1)


Здесь я создал демонстрацию: LocationTracker-WorkManager

MyWorker.java

public class MyWorker extends Worker {

    private static final String TAG = "MyWorker";

    /**
     * The desired interval for location updates. Inexact. Updates may be more or less frequent.
     */
    private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;

    /**
     * The fastest rate for active location updates. Updates will never be more frequent
     * than this value.
     */
    private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
            UPDATE_INTERVAL_IN_MILLISECONDS / 2;
    /**
     * The current location.
     */
    private Location mLocation;

    /**
     * Provides access to the Fused Location Provider API.
     */
    private FusedLocationProviderClient mFusedLocationClient;

    private Context mContext;
    /**
     * Callback for changes in location.
     */
    private LocationCallback mLocationCallback;

    public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
        mContext = context;
    }

    @NonNull
    @Override
    public Result doWork() {
        Log.d(TAG, "doWork: Done");

                mFusedLocationClient = LocationServices.getFusedLocationProviderClient(mContext);
                mLocationCallback = new LocationCallback() {
                    @Override
                    public void onLocationResult(LocationResult locationResult) {
                        super.onLocationResult(locationResult);
                    }
                };

                LocationRequest mLocationRequest = new LocationRequest();
                mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
                mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
                mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

                try {
                    mFusedLocationClient
                            .getLastLocation()
                            .addOnCompleteListener(new OnCompleteListener<Location>() {
                                @Override
                                public void onComplete(@NonNull Task<Location> task) {
                                    if (task.isSuccessful() && task.getResult() != null) {
                                        mLocation = task.getResult();
                                        Log.d(TAG, "Location : " + mLocation);
                                        mFusedLocationClient.removeLocationUpdates(mLocationCallback);
                                    } else {
                                        Log.w(TAG, "Failed to get location.");
                                    }
                                }
                            });
                } catch (SecurityException unlikely) {
                    Log.e(TAG, "Lost location permission." + unlikely);
                }

                try {
                    mFusedLocationClient.requestLocationUpdates(mLocationRequest, null);
                } catch (SecurityException unlikely) {
                    //Utils.setRequestingLocationUpdates(this, false);
                    Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
                }

        } catch (ParseException ignored) {

        }

        return Result.success();
    }
}

Как запустить воркер:

PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(MyWorker.class, 15, TimeUnit.MINUTES)
                            .addTag(TAG)
                            .build();
WorkManager.getInstance().enqueueUniquePeriodicWork("Location", ExistingPeriodicWorkPolicy.REPLACE, periodicWork);

Надеюсь, это будет полезно. Дайте мне знать, если у вас возникнут проблемы. Спасибо.

person Pratik Butani    schedule 14.06.2019
comment
Очень интересно. Вижу, работает даже после перезапуска. Так что это, кажется, путь. Придется дальше поиграть с идеей, которая у меня возникла. Спасибо за предоставленное решение. - person individual8; 14.06.2019
comment
Это ответило на мой вопрос. Спасибо. - person individual8; 19.06.2019
comment
Этот ответ требует больше голосов, он решает множество специфических проблем людей, в том числе и мою. - person barnacle.m; 09.09.2019
comment
@PratikButaniAndroidDev в настоящее время работает над способом сделать это, но для запроса нового обновления местоположения, используя ListenableWorker с concurrent-futures из workmanager - person barnacle.m; 09.09.2019
comment
Разве он не возвращает успех немедленно, а обратный вызов просто не запускается? Я рекомендую прочитать этот раздел developer.android.com/topic/libraries/architecture / workmanager / - person Bartek Pacia; 21.09.2019
comment
@Baftek: да, мы можем использовать listenableworker - person Pratik Butani; 09.01.2020
comment
Привет, Pratik, как насчет получения местоположения в фоновом режиме при удалении приложения. Я проверил ваш проект, но в нем нет фона - person Tahir Hussain Mir; 04.09.2020
comment
Вы проверили, распечатав несколько журналов в doWork()? Он будет вызываться в фоновом режиме. Минимальный интервал - 15 минут. - person Pratik Butani; 04.09.2020