【问题标题】:Google Maps API 2 MapView Not UpdatingGoogle Maps API 2 MapView 未更新
【发布时间】:2019-11-14 15:08:08
【问题描述】:

我在 Android 应用程序中显示 Google Maps API v2 MapView,但奇怪的是它没有以一致的方式正确更新。我正在使用 GPS 更新地图位置(尝试了 LocationManager 和 LocationClient),尽管地图移动到该位置,但大约百分之五十的时间街道名称图层无法更新或模糊/模糊部分失败更新——直到我手动拖动(滚动)地图。然后整个地图会立即更新。我已经在应用程序中剥离了很多处理,看看我是否以某种方式阻止了刷新,但这并没有产生任何影响。

我在 onCameraChange 中插入了一个 mapView.invalidate() 调用,但奇怪的是,这似乎使问题更容易发生(尽管仍然不是 100% 的时间)。

我正在按照 MapView 的要求实现所有 Activity 回调。

有人在 Android 上使用 Google Map API v2 遇到过类似的问题吗?如果是,您是否确定了原因以及您是如何解决的?

【问题讨论】:

  • 您检查过您的互联网连接吗?它必须不断提取这些数据。
  • 网络瓶颈是我首先考虑的问题之一。我认为解决方案是下面的 CancelableCallback。谢谢。
  • 我建议您将 Polaris2 作为第三方库,这对于应用内的所有此类功能非常有用 :) 您可以使用 danny 的解决方案,您将拥有很多非常有用的功能@ 987654321@

标签: android google-maps google-maps-android-api-2


【解决方案1】:

可以这么说,你必须让地图呼吸。

animateCameraCancelableCallback 一起使用,然后当动画完成时,您将收到对onFinish() 的回调,开始下一个动画。

public class KmlReader extends ActionBarActivity implements
    CancelableCallback {


@Override
public void onFinish() {
    startAnimation(); // start next map movement
}


@Override
public void onCancel() {
    //Called when user interacts with the map while it is moving.
}


public void startAnimation(){

cameraPosition = mMap.getCameraPosition();    
LatLng ll = new LatLng(expectedLocation.getLatitude(),
                    expectedLocation.getLongitude());
            cb.zoom(cameraPosition.zoom)
            // previous camera tilt
                    .tilt(cameraPosition.tilt)
                    // new expected destination
                    .target(ll)
                    // north up or heading view
                    .bearing((isHeading) ? bearing : 0f);
            cameraPosition = cb.build();
            CameraUpdate update = CameraUpdateFactory
                    .newCameraPosition(cameraPosition);
            mMap.animateCamera(update, working_interval, this);
}

* 编辑这是我现在正在处理的代码。* 它使用 asynctask 进行计算。我已经对其进行了步行测试,但尚未在车辆中对其进行测试。

private static CameraPosition currentCameraPosition;
private static com.google.android.gms.maps.model.CameraPosition.Builder cameraPositionBuilder;
private volatile CameraUpdate nextCameraUpdate;
// updates 
private static final long UPDATE_INTERVAL = 2500;
// fastest 
private static final int FASTEST_INTERVAL = 2500;
private static int working_interval = 5000; 
private volatile boolean isAnimating;


// Define the callback method that receives location updates
@SuppressLint("NewApi")
@Override
public void onLocationChanged(Location location) {
    Log.d("test", Boolean.toString(isAnimating)  +" onlocation");
    currentCameraPosition = mMap.getCameraPosition();

    NewCameraUpdateTask newCameraUpdateTask = new NewCameraUpdateTask();

// This task must run async
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    newCameraUpdateTask.executeOnExecutor(
            AsyncTask.THREAD_POOL_EXECUTOR, location);
} else {
    newCameraUpdateTask.execute(location);
}
    // speed display
    setMetersPerSecond(location.getSpeed());
}

// create a newCameraUpdate to move the map with
private class NewCameraUpdateTask extends
        AsyncTask<Location, Void, CameraUpdate> {

    @Override
    protected CameraUpdate doInBackground(Location... params) {
        Location workingLocation = null;
        CameraUpdate newCameraUpdate = null;

        float bearing = 0f;
        float speed = 0f;

        for (Location mlocation : params) {
            speed = mlocation.getSpeed();

            // camera position is saved before the start of each animation.
            LatLng ll;

        if (!mlocation.hasBearing() || speed == 0) {
            workingLocation = mlocation;
            // previous bearing
        } else {
            // current bearing
            bearing = mlocation.getBearing();
            // calculate the age of the location
            // atempt for animation to end a little bit past when
            // the
            // next
            // location arrives.
            // (location.getSpeed()m/s)(1/1000 interval seconds)(
            // 1/1000
            // km/m)
            // (1/6371 radians/km) = radians/6371000000.0
            double expectedDistance = working_interval / 6371000000.0
                    * speed;

            // latitude in Radians
            double currentLatitude = Math.toRadians(mlocation
                    .getLatitude());
            // longitude in Radians
            double currentlongitude = Math.toRadians(mlocation
                    .getLongitude());

            double calcBearing = Math.toRadians(bearing);

            // the camera position is needed so I can put in the
            // previous camera bearing when the location has no
            // bearing. This should prevent the map from
            // zooming to north when the device stops moving.

            // calculate the expected latitude and longitude based
            // on
            // staring
            // location
            // , bearing, and distance
            double sincurrentLatitude = Math.sin(currentLatitude);
            double coscurrentLatitude = Math.cos(currentLatitude);
            double cosexpectedDistance = Math.cos(expectedDistance);
            double sinexpectedDistance = Math.sin(expectedDistance);

            double expectedLatitude = Math.asin(sincurrentLatitude
                    * cosexpectedDistance + coscurrentLatitude
                    * sinexpectedDistance * Math.cos(calcBearing));
            double a = Math.atan2(
                    Math.sin(calcBearing) * sinexpectedDistance
                            * coscurrentLatitude,
                    cosexpectedDistance - sincurrentLatitude
                            * Math.sin(expectedLatitude));
            double expectedLongitude = currentlongitude + a;
            expectedLongitude = (expectedLongitude + PI3) % PI2 - PI;

            // convert to degrees for the expected destination
            double expectedLongitudeDestination = Math
                    .toDegrees(expectedLongitude);
            double expectedLatitudeDestination = Math
                    .toDegrees(expectedLatitude);

            mlocation.setLatitude(expectedLatitudeDestination);
            mlocation.setLongitude(expectedLongitudeDestination);
            workingLocation = mlocation;

        }
        break;
    }

    if (workingLocation != null) {
        if (workingLocation.hasBearing()) {
            bearing = workingLocation.getBearing();
        } else {
            bearing = currentCameraPosition.bearing;
        }
        LatLng ll = new LatLng(workingLocation.getLatitude(),
                workingLocation.getLongitude());
        cameraPositionBuilder.zoom(currentCameraPosition.zoom)
        // previous camera tilt
                .tilt(currentCameraPosition.tilt)
                // new expected destination
                .target(ll)
                // north up or heading view
                .bearing((isHeading) ? bearing : 0f);
        newCameraUpdate = CameraUpdateFactory
                .newCameraPosition(cameraPositionBuilder.build());
    }

    return newCameraUpdate;
}

@Override
protected void onPostExecute(CameraUpdate result) {
    Log.d("test", Boolean.toString(isAnimating) + " onPostExecute");
    if (result != null) {
        nextCameraUpdate = result;
        // stop the currently playing animation
        // there is a new one ready to start
        if (isAnimating) {
            if (mMap != null) {
                mMap.stopAnimation();
            }
        }
        // start the next animation
        startAnimation();
        Log.d("test", Boolean.toString(isAnimating)  +" onPostExecuteComplete");
    }


}
}


// called when map animation has been canceled
@Override
public void onCancel() {
    Log.d("test", Boolean.toString(isAnimating)  +" oncancel");
    isAnimating = false;
}

@Override
public void onFinish() {
    Log.d("test", Boolean.toString(isAnimating)  +" onfinish");
    isAnimating = false;
    startAnimation();

    // call to start saved animation.
}

private void startAnimation() {
    Log.d("test", Boolean.toString(isAnimating)  +" startAnimation");
    if (action_track) {
        if (isAnimating) {
            return;
        }
        if (nextCameraUpdate == null) {
            return;
        }
        // abort if animating
        isAnimating = true;
        CameraUpdate animateCameraUpdate = nextCameraUpdate;
        nextCameraUpdate = null;
        mMap.animateCamera(animateCameraUpdate, working_interval, this);
        Log.d("test", Boolean.toString(isAnimating)  +" startanimateCamera");
    }
}

【讨论】:

  • 好东西,没见过这个实现
  • 很好的答案!谢谢。现在还有一个棘手的部分:如何根据异步位置更新来启动和停止动画。有时位置更新每秒会发生几次,有时如果您不移动,则在蓝月亮中一次。在 onFinish 中清除了 Gatekeeper 标志? (试过这个,还没有工作。)大小为 1 的位置队列?哪里有例子吗?
  • 好的,我明白了。使用 AtomicBoolean 作为看门人标志似乎可以解决问题。
  • 这是棘手的部分。我可以用坐标在死点移动地图,这是可以接受的移动,但我需要一些触发向导来告诉我如何用靠近地图底部的坐标移动地图?
  • 我正在发布我的整个实现。今天失败了,但我的手机上可能没有正确的 apk。
【解决方案2】:

如果有人遇到此问题,关键是保持animateCamera 调用的动画持续时间小于您调用animateCamera 方法的频率。

例如,如果您每隔1000ms 调用一次animateCamera,则将动画相机持续时间设置为小于该值。

map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, ZOOM_LEVEL), 900, null)

如果您的 animateCamera 呼叫不是在固定时间被调用,那么 danny117 使用回调触发下一次相机更新的答案将完美运行。

【讨论】:

    【解决方案3】:

    受 danny117 解决方案的启发,我找到了一个更简单的解决方案。 我将位置请求更新设置为每 5 毫秒,并将动画相机持续时间设置为 2.5 毫秒。问题解决了

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 2012-11-21
      • 1970-01-01
      • 2011-09-05
      • 2013-02-14
      相关资源
      最近更新 更多