如何使用地理围栏避免 Android 中的多个回调级别

How to avoid multiple callback levels in Android with geofences

我正在尝试创建一个 Android 应用程序,其中包含从外部 API 加载的地理围栏位置。我使用改造来进行 aysnc 调用。问题是 googleApiClient 和外部 API 调用都是异步的。所以我不知道哪个先完成才能启动地理围栏。

如果我在 googleApiClientonConnected() 中启动地理围栏,我可能还没有来自 API 的 LatLng。但是,如果我从 API 的回调启动地理围栏,googleApiClient 可能尚未加载。

除了在 googleApiClientonConnected() 中执行异步 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();
}

}