使用CameraUpdateFactory.newLatLngBounds崩溃的moveCamera

Lee*_*Lee 94 android android-mapview google-maps-android-api-2

我正在使用新的Android Google Maps API.

我创建了一个包含MapFragment的活动.在活动中,onResume我将标记设置为GoogleMap对象,然后为地图定义包含所有标记的边界框.

这是使用以下伪代码:

LatLngBounds.Builder builder = new LatLngBounds.Builder();
while(data) {
   LatLng latlng = getPosition();
   builder.include(latlng);
}
CameraUpdate cameraUpdate = CameraUpdateFactory
   .newLatLngBounds(builder.build(), 10);
map.moveCamera(cameraUpdate);
Run Code Online (Sandbox Code Playgroud)

调用map.moveCamera()导致我的应用程序崩溃与以下堆栈:

Caused by: java.lang.IllegalStateException: 
    Map size should not be 0. Most likely, layout has not yet 

    at maps.am.r.b(Unknown Source)
    at maps.y.q.a(Unknown Source)
    at maps.y.au.a(Unknown Source)
    at maps.y.ae.moveCamera(Unknown Source)
    at com.google.android.gms.maps.internal.IGoogleMapDelegate$Stub
        .onTransact(IGoogleMapDelegate.java:83)
    at android.os.Binder.transact(Binder.java:310)
    at com.google.android.gms.maps.internal.IGoogleMapDelegate$a$a
        .moveCamera(Unknown Source)
    at com.google.android.gms.maps.GoogleMap.moveCamera(Unknown Source)
    at ShowMapActivity.drawMapMarkers(ShowMapActivity.java:91)
    at ShowMapActivity.onResume(ShowMapActivity.java:58)
    at android.app.Instrumentation
        .callActivityOnResume(Instrumentation.java:1185)
    at android.app.Activity.performResume(Activity.java:5182)
    at android.app.ActivityThread
        .performResumeActivity(ActivityThread.java:2732)
Run Code Online (Sandbox Code Playgroud)

如果 - 而不是newLatLngBounds()工厂方法我使用newLatLngZoom()方法,那么不会发生相同的陷阱.

是将onResume标记绘制到GoogleMap对象上的最佳位置,还是应该绘制标记并将摄像机位置设置在其他位置?

Pau*_*kov 133

您可以在OnCameraChangeListener中使用简单的newLatLngBounds方法.一切都将完美运行,您不需要计算屏幕尺寸.此事件发生在地图大小计算后(据我所知).

例:

map.setOnCameraChangeListener(new OnCameraChangeListener() {

    @Override
    public void onCameraChange(CameraPosition arg0) {
        // Move camera.
        map.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 10));
        // Remove listener to prevent position reset on camera move.
        map.setOnCameraChangeListener(null);
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 也许可以添加**map.moveCamera(CameraUpdateFactory.scrollBy(1,1));**上面的代码后会出现这个伎俩? (4认同)
  • @SteelRat这就是我反对使用该解决方案的原因.你永远不知道google什么时候改变它,或者即使它在所有Android版本或设备上都是这样的. (3认同)
  • 现在不推荐使用`setOnCameraChangeListener` (3认同)

小智 56

那些答案很好,但我会采用不同的方法,更简单的方法.如果该方法仅在布局后布局,则只需等待它:

map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
    @Override
    public void onMapLoaded() {
        map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30));
    }
});
Run Code Online (Sandbox Code Playgroud)

  • docs中对此方法发出警告:“如果由于连接问题而导致地图永远无法加载,或者*由于用户不断与地图互动而导致地图不断变化且从未完成加载,则不会触发此事件。” (强调我的)。 (2认同)

Lee*_*Lee 50

好的,我把它解决了.如此处所述,API不能在预布局之前使用.

要使用的正确API描述为:

注意:如果要在地图经过布局后用于移动相机,则仅使用更简单的方法newLatLngBounds(boundary,padding)生成CameraUpdate.在布局期间,API会计算正确投影边界框所需的地图显示边界.相比较而言,可以使用通过在任何时间更复杂的方法newLatLngBounds(边界,宽度,高度,填充)返回的CameraUpdate,甚至在地图已布局发生了,因为API从您传递参数计算显示边界.

为了解决这个问题,我计算了我的屏幕尺寸并提供了宽度和高度

public static CameraUpdate newLatLngBounds(
    LatLngBounds bounds, int width, int height, int padding)
Run Code Online (Sandbox Code Playgroud)

然后,这允许我指定边界框预布局.

  • 但是,如果地图不占用整个屏幕怎么办? (18认同)
  • 您可以显示如何根据屏幕尺寸进行计算吗? (2认同)

Dan*_*ato 34

解决方案比那简单....

// Pan to see all markers in view.
try {
    this.gmap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
} catch (IllegalStateException e) {
    // layout not yet initialized
    final View mapView = getFragmentManager()
       .findFragmentById(R.id.map).getView();
    if (mapView.getViewTreeObserver().isAlive()) {
        mapView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @SuppressWarnings("deprecation")
            @SuppressLint("NewApi")
            // We check which build version we are using.
            @Override
            public void onGlobalLayout() {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                    mapView.getViewTreeObserver()
                        .removeGlobalOnLayoutListener(this);
                } else {
                    mapView.getViewTreeObserver()
                        .removeOnGlobalLayoutListener(this);
                }
                gmap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

IllegalStateException而是在视图上捕获并使用全局侦听器.使用其他方法预先设置边界大小(预布局)意味着您必须计算THE VIEW的大小,而不是屏幕设备.如果您使用地图全屏显示并且不使用片段,则它们仅匹配.


小智 15

这是我的修复,只是等待,直到在这种情况下加载地图.

final int padding = getResources().getDimensionPixelSize(R.dimen.spacing);    

try {
    mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(pCameraBounds, padding));
} catch (IllegalStateException ise) {

    mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {

        @Override
        public void onMapLoaded() {
            mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(pCameraBounds, padding));
        }
    });
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*enT 14

添加和删​​除标记可以在布局完成之前完成,但移动相机不能(除了使用newLatLngBounds(boundary, padding)OP的答案中所述).

可能执行初始相机更新的最佳场所是使用一次性OnGlobalLayoutListener如图谷歌的示例代码,例如,见下面摘自setUpMap()MarkerDemoActivity.java:

// Pan to see all markers in view.
// Cannot zoom to bounds until the map has a size.
final View mapView = getSupportFragmentManager()
    .findFragmentById(R.id.map).getView();
if (mapView.getViewTreeObserver().isAlive()) {
    mapView.getViewTreeObserver().addOnGlobalLayoutListener(
    new OnGlobalLayoutListener() {
        @SuppressLint("NewApi") // We check which build version we are using.
        @Override
        public void onGlobalLayout() {
            LatLngBounds bounds = new LatLngBounds.Builder()
                    .include(PERTH)
                    .include(SYDNEY)
                    .include(ADELAIDE)
                    .include(BRISBANE)
                    .include(MELBOURNE)
                    .build();
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
              mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            } else {
              mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
            mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
        }
    });
}
Run Code Online (Sandbox Code Playgroud)


Teo*_*nke 12

接受的答案对我不起作用,因为我必须在我的应用程序的不同位置使用相同的代码.

我没有等待相机改变,而是根据Lee建议的指定地图大小创建了一个简单的解决方案.这是为了您的地图是屏幕的大小.

// Gets screen size
int width = getResources().getDisplayMetrics().widthPixels;
int height = getResources().getDisplayMetrics().heightPixels;
// Calls moveCamera passing screen size as parameters
map.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), width, height, 10));
Run Code Online (Sandbox Code Playgroud)

希望它可以帮助别人!


the*_*ang 8

正如评论中指出的那样,接受的答案是有点hacky.实施后,我注意到IllegalStateException分析中有大量可接受的日志.我所使用的溶液是添加OnMapLoadedCallback在其中CameraUpdate被执行.回调被添加到GoogleMap.地图完全加载后,将执行相机更新.

这会导致地图在执行相机更新之前简要显示缩小(0,0)视图.我觉得这比造成崩溃或依赖无证件行为更容易接受.


Ram*_*thi 5

 map.moveCamera(CameraUpdateFactory.newLatLngZoom(bounds.getCenter(),10));
Run Code Online (Sandbox Code Playgroud)

用这个它对我来说很有用