【发布时间】:2020-05-29 22:56:01
【问题描述】:
我已在应用程序中实施地理围栏。但问题是每当我打开应用程序时,都会再次添加地理围栏。因此,如果我们在地理围栏区域内,它会立即触发进入警报。
当前实施 - 工作流程:
- 用户打开应用程序
- 名为
GeoFenceMakerService的服务从主活动启动。 -
GeoFenceMakerService调用 API 并从服务器获取地点的详细信息(纬度、经度、地点 ID、地点名称、半径等)。可以有一个或多个地方。 - 地点详细信息(API 结果)将保存到本地数据库。
- 如果有 1 个或多个地点,则为每个地点构建地理围栏对象 (initializeGeoFence)。
- 构建地理围栏请求并创建待定意图。这将传递给地理围栏客户端以添加地理围栏。 (
geofencingClient.addGeofences(getGeofencingRequest(), createGeoFencePendingIntent())) - 添加地理围栏后停止
GeoFenceMakerService。
问题:
createGeoFencePendingIntent() 总是在创建新的待处理意图,如果我们在打开应用程序时处于地理围栏区域内,可能会触发进入警报。
从堆栈溢出中找到了类似的解决方案: 是使用共享首选项对待处理的意图进行检查。您可以从here 看到完整的解决方案。但我对此并不满意,因为,“最好检查未决意图是否存在,而不是在我们添加地理围栏的共享首选项中写入,因为当我们重新启动手机或更改位置精度时,它们会被删除并且挂起的意图不再存在,但不会更新共享首选项” - (其中一个已经提到作为对所提到的解决方案的评论)。
需要当前的解决方案: 需要检查地理围栏是否已经添加,只有在不存在的情况下才添加地理围栏。
我附上整个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;
}
}
【问题讨论】:
标签: android android-location geofencing android-geofence