Я реализовал геозону в приложении. Но проблема в том, что всякий раз, когда я открываю приложение, геозона добавляется снова. Таким образом, это немедленно приводит к срабатыванию предупреждения о входе, если мы находимся в зоне геозоны.
Текущая реализация - рабочий процесс:
- Пользователь открывает приложение
- Служба с именем
GeoFenceMakerService
запускается из основного действия. GeoFenceMakerService
вызывает вызов API и извлекает сведения о местах (Lat, Long, Place Id, Place Name, Radius и др.). c) с сервера. Может быть одно или несколько мест. - Информация о месте (результат API) будет сохранена в локальной базе данных.
- Если имеется 1 или несколько мест, то создается объект геозоны для каждое место (initializeGeoFence).
- Создание запроса на геозону и создание отложенного намерения. Это будет передано клиенту Geofencing для добавления геозоны. (
geofencingClient.addGeofences(getGeofencingRequest(), createGeoFencePendingIntent())
) - Остановите
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;
}
}