Geofence PendingIntent всегда становится равным нулю - PullRequest
0 голосов
/ 14 февраля 2020

Я реализовал геозону в приложении. Но проблема в том, что всякий раз, когда я открываю приложение, геозона добавляется снова. Таким образом, это немедленно приводит к срабатыванию предупреждения о входе, если мы находимся в зоне геозоны.

Текущая реализация - рабочий процесс:

  1. Пользователь открывает приложение
  2. Служба с именем GeoFenceMakerService запускается из основного действия.
  3. GeoFenceMakerService вызывает вызов API и извлекает сведения о местах (Lat, Long, Place Id, Place Name, Radius и др.). c) с сервера. Может быть одно или несколько мест.
  4. Информация о месте (результат API) будет сохранена в локальной базе данных.
  5. Если имеется 1 или несколько мест, то создается объект геозоны для каждое место (initializeGeoFence).
  6. Создание запроса на геозону и создание отложенного намерения. Это будет передано клиенту Geofencing для добавления геозоны. (geofencingClient.addGeofences(getGeofencingRequest(), createGeoFencePendingIntent()))
  7. Остановите GeoFenceMakerService после добавления геозон.

Проблема: createGeoFencePendingIntent() всегда создает новое отложенное намерение и может Вызывать предупреждение при входе, если мы находимся в области геозоны, когда открываем приложение.

Аналогичное решение, найденное из-за переполнения стека: Была реализация проверки с использованием общих настроек для ожидающего намерения. Вы можете увидеть полное решение с здесь . Но меня это не устраивает, потому что, "лучше проверить, существует ли ожидающее намерение, а не записывать в общих настройках, что мы добавили геозоны, потому что когда мы перезагружаем телефон или меняем точность определения местоположения, они удаляются и ожидающее намерение больше не существует, но общие предпочтения не будут обновлены " - (Один из них уже упоминался там как комментарий к упомянутому решению).

Требуемое текущее решение: Необходимо проверить, добавлена ​​ли уже геозона, и добавлять геозону, только если ее нет.

Я прилагаю весь код GeoFenceMakerService для справки.

package com.****.*****.services;

import android.Manifest;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;

import com.****.****.api.Api;
import com.****.****.api.ApiMethods;
import com.****.****.models.Place;
import com.****.****.models.response.PlacesListResponse;
import com.****.****.receiver.GeofenceBroadcastReceiver;
import com.****.****.utils.DatabaseManager;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingClient;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;

import java.util.ArrayList;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class GeoFenceMakerService extends Service {

    public static final String TAG = "GeoFenceMakerService";
    private ArrayList<Place> places = null;
    private GeofencingClient geofencingClient = null;
    private ArrayList<Geofence> geofenceList = null;
    private PendingIntent geoFencePendingIntent;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        Log.d(TAG, "GeoFenceMakerService Created");
        geofencingClient = LocationServices.getGeofencingClient(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //handleStart(intent, startId);
        Log.d(TAG, "Inside onStartCommand");
        getPlacesList();
        return START_NOT_STICKY;
    }

    private void getPlacesList() {
        Log.i(TAG, "getPlacesList: ");
        ApiMethods apiMethods;
        Call<PlacesListResponse> listResponseCall;
        apiMethods = Api.getInstance(this);
        listResponseCall = apiMethods.getAllPlacesList();
        Log.i(TAG, "Getting places list from API");
        listResponseCall.enqueue(new Callback<PlacesListResponse>() {
            @Override
            public void onResponse(Call<PlacesListResponse> call, Response<PlacesListResponse> response) {
                if (response.code() == Api.STATUS_200) {
                    handlePlacesList(response.body());
                } else {
                    Log.e(TAG, "Get places list api failed with code: " + response.code());
                }
            }

            @Override
            public void onFailure(Call<PlacesListResponse> call, Throwable t) {
                Log.e(TAG, "Get places list api failed" + t.getLocalizedMessage());
            }
        });
    }

    private void handlePlacesList(PlacesListResponse placesListResponse) {
        Log.i(TAG, "handlePlacesList: ");
        DatabaseManager databaseManager = new DatabaseManager(this);

        if (placesListResponse != null) {


            Log.i(TAG, "Got places list response");
            places = placesListResponse.getPlaces();
            databaseManager.savePlacesToDatabase(places);
            if (!(places.size() == 0)) {
                initializeGeoFence();
                addGeoFence2();
            }
           /* initializeGeoFence();
            addGeoFence2();*/
        } else {

            Log.e(TAG, "Places list response is null");

        }
    }

    private void initializeGeoFence() {
        // Toast.makeText(this, "initializing geo fence", Toast.LENGTH_LONG).show();
        Log.i(TAG, "initializing geo fence");
        Geofence geofence;
        geofenceList = new ArrayList<>();
        for (Place place : places) {
            Log.i(TAG, "Adding geofence at " + place.getLatitude() + ", " + place.getLongitude());
            // @TODO Fetch and set the Geofence Radius dynamically
            geofence = new Geofence.Builder()
                    // Set the request ID of the geofence. This is a string to identify this
                    // geofence.
                    .setRequestId(place.getPlaceId() + "")
                    .setCircularRegion(
                            place.getLatitude(),
                            place.getLongitude(),
                            500f)
                    .setExpirationDuration(60 * 60 * 1000)
                    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
                    .build();

            geofenceList.add(geofence);
        }
    }

    private void addGeoFence2() {
        Log.i(TAG, "addGeoFence2: ");
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Make sure permission is granted before starting the service. NOTE: Requesting permission from Service is not allowed.
            return;
        }
        geofencingClient.addGeofences(getGeofencingRequest(), createGeoFencePendingIntent())
                .addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        Log.i(TAG, "Geo fence added");
                        // Toast.makeText(HomeActivity.this, "Geo fence added", Toast.LENGTH_LONG).show();
                        GeoFenceMakerService.this.stopSelf();
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.e(TAG, "Geo fence add failed. ");
                        e.printStackTrace();
                        // Toast.makeText(HomeActivity.this, "Geo fence add failed", Toast.LENGTH_LONG).show();
                        GeoFenceMakerService.this.stopSelf();
                    }
                });
    }

    private GeofencingRequest getGeofencingRequest() {

        // Toast.makeText(this, "getGeofencingRequest", Toast.LENGTH_LONG).show();
        Log.i(TAG, "getGeofencingRequest");
        GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
        builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
        builder.addGeofences(geofenceList);
        return builder.build();
    }

    private PendingIntent createGeoFencePendingIntent() {
        Intent intent;

        Log.d(TAG, "createGeoFencePendingIntent");

        if (geoFencePendingIntent == null) {
            Log.i(TAG, "GeoFence pending intent is null. Creating new instance");

            intent = new Intent(this, GeofenceBroadcastReceiver.class);
            // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
            // calling addGeofences() and removeGeofences().
            geoFencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.
                    FLAG_UPDATE_CURRENT);


        }

        return geoFencePendingIntent;
    }

}

1 Ответ

0 голосов
/ 14 февраля 2020

Намерение, отправленное из Location Services, может инициировать различные действия в вашем приложении, но вы не должны запускать действие или фрагмент, потому что компоненты должны становиться видимыми только в ответ на действие пользователя. Во многих случаях BroadcastReceiver является хорошим способом обработки перехода геозоны. BroadcastReceiver получает обновления, когда происходит событие, такое как переход в геозону или из нее, и может начать длительную фоновую работу.

отметьте здесь

private PendingIntent getGeofencePendingIntent() {
    if (geofencePendingIntent != null) {
        return geofencePendingIntent;
    }
    Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
        
    geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    return geofencePendingIntent;
}
...