如何使用地理围栏避免 Android 中的多个回调级别
How to avoid multiple callback levels in Android with geofences
我正在尝试创建一个 Android 应用程序,其中包含从外部 API 加载的地理围栏位置。我使用改造来进行 aysnc 调用。问题是 googleApiClient
和外部 API 调用都是异步的。所以我不知道哪个先完成才能启动地理围栏。
如果我在 googleApiClient
的 onConnected()
中启动地理围栏,我可能还没有来自 API 的 LatLng。但是,如果我从 API 的回调启动地理围栏,googleApiClient
可能尚未加载。
除了在 googleApiClient
的 onConnected()
中执行异步 API 调用之外,我还能做些什么来处理这个问题。我试图避免多个回调级别。这是我的代码,目前不起作用,因为我认为 API 的结果在调用 startGeofences()
时还不存在:
public class GeofenceHelper implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
private List<Geofence> mGeofenceList = new ArrayList<>();
private GoogleApiClient googleApiClient;
public GeofenceHelper(Activity context){
this.context = context;
permissionsHelper = new PermissionsHelper(context, REQ_PERMISSION);
buildGoogleApiClient();
geofencePointsRequest();
}
private void startGeofences() {
Log.i(TAG, "startGeofences()");
if (!googleApiClient.isConnected()) {
Log.d(TAG, "Not connected");
return;
}
if (permissionsHelper.checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult()
}
private void geofencePointsRequest() {
GeofenceAreasRequest response = new GeofenceAreasRequest();
response.getAllAreas(new GeofenceAreasResponse() {
@Override
public void onAreasLoaded(List<Point> points, int code) {
Log.i(TAG, "Responsecode: " + String.valueOf(code));
for (int i = 0; i < points.size(); i++) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(points.get(i).getName())
.setCircularRegion(
points.get(i).getLatitude(),
points.get(i).getLongitude(),
points.get(i).getRadius())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build());
}
}
});
}
private GeofencingRequest getGeofencingRequest() {
Log.d(TAG, "getGeofencingRequest");
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void start(){
googleApiClient.connect();
}
public void stop(){
googleApiClient.disconnect();
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.i(TAG, "google api connected");
startGeofences();
getLastKnownLocation();
}
}
试试这个方法
public class GeofenceHelper implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
private List<Geofence> mGeofenceList = new ArrayList<>();
private GoogleApiClient googleApiClient;
private List<Point> pointsList = null;
public GeofenceHelper(Activity context) {
this.context = context;
permissionsHelper = new PermissionsHelper(context, REQ_PERMISSION);
// let both work in parallel
buildGoogleApiClient();
geofencePointsRequest();
}
private void startGeofences() {
Log.i(TAG, "startGeofences()");
if (!googleApiClient.isConnected()) {
Log.d(TAG, "Not connected");
return;
}
if (permissionsHelper.checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult()
}
private void registerGeofences() {
if (pointsList != null) {
// populate data in list
for (int i = 0; i < pointsList.size(); i++) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(pointsList.get(i).getName())
.setCircularRegion(
pointsList.get(i).getLatitude(),
pointsList.get(i).getLongitude(),
pointsList.get(i).getRadius())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build());
}
// this will actually register geofences
startGeofences();
}
}
private void geofencePointsRequest() {
GeofenceAreasRequest response = new GeofenceAreasRequest();
response.getAllAreas(new GeofenceAreasResponse() {
@Override
public void onAreasLoaded(List<Point> points, int code) {
Log.i(TAG, "Responsecode: " + String.valueOf(code));
pointsList = points;
registerGeofences();
}
});
}
private GeofencingRequest getGeofencingRequest() {
Log.d(TAG, "getGeofencingRequest");
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void start() {
googleApiClient.connect();
}
public void stop() {
googleApiClient.disconnect();
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.i(TAG, "google api connected");
getLastKnownLocation();
registerGeofences();
}
}
我正在尝试创建一个 Android 应用程序,其中包含从外部 API 加载的地理围栏位置。我使用改造来进行 aysnc 调用。问题是 googleApiClient
和外部 API 调用都是异步的。所以我不知道哪个先完成才能启动地理围栏。
如果我在 googleApiClient
的 onConnected()
中启动地理围栏,我可能还没有来自 API 的 LatLng。但是,如果我从 API 的回调启动地理围栏,googleApiClient
可能尚未加载。
除了在 googleApiClient
的 onConnected()
中执行异步 API 调用之外,我还能做些什么来处理这个问题。我试图避免多个回调级别。这是我的代码,目前不起作用,因为我认为 API 的结果在调用 startGeofences()
时还不存在:
public class GeofenceHelper implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
private List<Geofence> mGeofenceList = new ArrayList<>();
private GoogleApiClient googleApiClient;
public GeofenceHelper(Activity context){
this.context = context;
permissionsHelper = new PermissionsHelper(context, REQ_PERMISSION);
buildGoogleApiClient();
geofencePointsRequest();
}
private void startGeofences() {
Log.i(TAG, "startGeofences()");
if (!googleApiClient.isConnected()) {
Log.d(TAG, "Not connected");
return;
}
if (permissionsHelper.checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult()
}
private void geofencePointsRequest() {
GeofenceAreasRequest response = new GeofenceAreasRequest();
response.getAllAreas(new GeofenceAreasResponse() {
@Override
public void onAreasLoaded(List<Point> points, int code) {
Log.i(TAG, "Responsecode: " + String.valueOf(code));
for (int i = 0; i < points.size(); i++) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(points.get(i).getName())
.setCircularRegion(
points.get(i).getLatitude(),
points.get(i).getLongitude(),
points.get(i).getRadius())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build());
}
}
});
}
private GeofencingRequest getGeofencingRequest() {
Log.d(TAG, "getGeofencingRequest");
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void start(){
googleApiClient.connect();
}
public void stop(){
googleApiClient.disconnect();
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.i(TAG, "google api connected");
startGeofences();
getLastKnownLocation();
}
}
试试这个方法
public class GeofenceHelper implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
private List<Geofence> mGeofenceList = new ArrayList<>();
private GoogleApiClient googleApiClient;
private List<Point> pointsList = null;
public GeofenceHelper(Activity context) {
this.context = context;
permissionsHelper = new PermissionsHelper(context, REQ_PERMISSION);
// let both work in parallel
buildGoogleApiClient();
geofencePointsRequest();
}
private void startGeofences() {
Log.i(TAG, "startGeofences()");
if (!googleApiClient.isConnected()) {
Log.d(TAG, "Not connected");
return;
}
if (permissionsHelper.checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult()
}
private void registerGeofences() {
if (pointsList != null) {
// populate data in list
for (int i = 0; i < pointsList.size(); i++) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(pointsList.get(i).getName())
.setCircularRegion(
pointsList.get(i).getLatitude(),
pointsList.get(i).getLongitude(),
pointsList.get(i).getRadius())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build());
}
// this will actually register geofences
startGeofences();
}
}
private void geofencePointsRequest() {
GeofenceAreasRequest response = new GeofenceAreasRequest();
response.getAllAreas(new GeofenceAreasResponse() {
@Override
public void onAreasLoaded(List<Point> points, int code) {
Log.i(TAG, "Responsecode: " + String.valueOf(code));
pointsList = points;
registerGeofences();
}
});
}
private GeofencingRequest getGeofencingRequest() {
Log.d(TAG, "getGeofencingRequest");
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void start() {
googleApiClient.connect();
}
public void stop() {
googleApiClient.disconnect();
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.i(TAG, "google api connected");
getLastKnownLocation();
registerGeofences();
}
}