我正在Android应用程序中显示Google Maps API v2 MapView,但奇怪的是,它没有以一致的方式正确更新。我正在使用GPS更新地图位置(同时尝试了LocationManager和LocationClient),尽管地图移动到了该位置,但大约有百分之五十的时间或者街道名称图层无法更新或者有一个模糊/模糊部分未能通过更新-直到我手动拖动(滚动)地图。然后整个地图立即更新。我已经剥离了应用程序中的许多处理程序,以查看是否由于某种原因阻止了刷新,但是并没有什么不同。
[我在onCameraChange中插入了mapView.invalidate()调用,但这似乎使问题更容易发生(尽管仍然不是100%的时间)。
我正在实现MapView所需的所有Activity回调。
[有人在Android上使用Google Map API v2遇到这样的问题吗?如果是这样,您是否确定了原因以及如何解决?
可以这么说,你必须让地图呼吸。
将animateCamera
与CancelableCallback
一起使用,然后在完成动画后会回叫到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");
}
}
受danny117解决方案的启发,我找到了一个更简单的解决方案。我将位置请求更新设置为每5毫秒,并将动画相机的持续时间设置为2.5毫秒。问题已解决
[如果有人遇到此问题,关键是使animateCamera
调用的动画持续时间小于您调用animateCamera
方法的频率。
例如,如果每animateCamera
调用一次1000ms
,请将动画摄像机的持续时间设置为小于该时间。>>
CameraUpdateFactory.newLatLngZoom(latLng, ZOOM_LEVEL), 900, null)
如果您的
animateCamera
通话不是在固定的时间被调用,那么danny117的使用回调触发下一个摄像机更新的答案将非常有效。