我正在尝试在后台获取GoogleMap(来自MapView)的快照,通过回调返回它并在ImageView中显示它。在这样做时,我试图尽可能使快照部分独立于布局(因此,试图避免在布局中添加MapView)。我尝试过以编程方式创建一个给定大小的MapView,在其上添加一些路径和引脚,获取快照并返回它(所有使用RxJava订阅)但我收到以下错误,应用程序正在关闭,甚至没有“ app停止工作“对话框。
FATAL EXCEPTION: androidmapsapi-Snapshot Process: com.package.name.debug, PID: 2159 java.lang.IllegalArgumentException: width and height must be > 0 at android.graphics.Bitmap.createBitmap(Bitmap.java:1013) at android.graphics.Bitmap.createBitmap(Bitmap.java:980) at android.graphics.Bitmap.createBitmap(Bitmap.java:930) at android.graphics.Bitmap.createBitmap(Bitmap.java:891) at com.google.maps.api.android.lib6.impl.ec.b(:com.google.android.gms.DynamiteModulesB@11975940:4) at com.google.maps.api.android.lib6.impl.bf.run(:com.google.android.gms.DynamiteModulesB@11975940:4) at java.lang.Thread.run(Thread.java:764)
以下是获取快照的代码
fun bitmapFor(mapData: MapData, specs: Specs): Single<Bitmap?> {
val mapView = MapView(context)
mapView.layoutParams = ViewGroup.LayoutParams(specs.mapWidth, specs.mapHeight)
return mapView.getMap()
.subscribeOn(AndroidSchedulers.mainThread())
.map { googleMap ->
setupMap(googleMap, mapData) // Adds paths and pins
googleMap
}
.flatMap { googleMap ->
googleMap.snapshot(mapData)
}
}
private fun MapView.getMap(): Single<GoogleMap> {
return Single.create { subscriber ->
val handler = Handler(Looper.getMainLooper())
handler.post {
onCreate(null)
onStart()
onResume()
getMapAsync { googleMap ->
subscriber.onSuccess(googleMap)
}
}
}
}
private fun GoogleMap.snapshot(mapData: MapData): Single<Bitmap> {
return Single.create { subscriber ->
snapshot { bitmap ->
saveMap(mapData.hashCode().toString(), bitmap)
subscriber.onSuccess(bitmap)
}
}
}
在UI类中,我正在做
viewModel.mapProvider
.bitmapFor(map, viewModel.mapData, Specs(map.measuredWidth, map.measuredHeight))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onMap, this::onError) // onMap set's the image bitmap
答案 0 :(得分:1)
请参阅更新!
似乎无法在隐身 MapView
的背景上获取Google Map快照,因为当地图不可见时,地图甚至没有开始加载。您可以为不可见MapVew
设置正确的尺寸(例如,基于this文章),但似乎它将是空白黑条,其中包含&#34; Google&#34;商标。可能最简单的解决方法 - 仍显示MapView
,但禁用其上的控件和手势:
`public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.getUiSettings().setAllGesturesEnabled(false);
...
}`
或通过Static Map API下载地图图像,并在下载的位图上本地绘制所需内容。
<强>更新强>
通过在创建时将Lite Mode设置为otherwise no map will appear,可以在不可见MapView
的背景上获取Google地图快照:
...
GoogleMapOptions options = new GoogleMapOptions()
.compassEnabled(false)
.mapToolbarEnabled(false)
.camera(CameraPosition.fromLatLngZoom(KYIV,15))
.liteMode(true);
mMapView = new MapView(this, options);
...
在MapView
通过onMapReady()
和measure()
调用启动地图图片加载时确定layout()
尺寸是必要的,而不是在加载地图图片后,它可以在onMapLoaded()
回调中获取:
mMapView.setDrawingCacheEnabled(true);
mMapView.measure(View.MeasureSpec.makeMeasureSpec(mMapWidth, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(mMapHeight, View.MeasureSpec.EXACTLY));
mMapView.layout(0, 0, mMapWidth, mMapHeight);
mMapView.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(mMapView.getDrawingCache()); // <- that is bitmap with map image
mMapView.setDrawingCacheEnabled(false);
必须在onCreate()
,之前致电MapView
对象上的getMapAsyhc()
。
完整源代码:
public class MainActivity extends AppCompatActivity {
private static final String MAP_VIEW_BUNDLE_KEY = "MapViewBundleKey";
static final LatLng KYIV = new LatLng(50.450311, 30.523730);
private ImageView mImageView;
private MapView mMapView;
// dimensions of map image
private int mMapWidth = 600;
private int mMapHeight = 800;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.image_view);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAP_VIEW_BUNDLE_KEY);
}
GoogleMapOptions options = new GoogleMapOptions()
.compassEnabled(false)
.mapToolbarEnabled(false)
.camera(CameraPosition.fromLatLngZoom(KYIV,15))
.liteMode(true);
mMapView = new MapView(this, options);
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
// form your card (add markers, path etc.) here:
googleMap.addMarker(new MarkerOptions()
.position(KYIV)
.title("Kyiv"));
// set map size in pixels and initiate image loading
mMapView.measure(View.MeasureSpec.makeMeasureSpec(mMapWidth, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(mMapHeight, View.MeasureSpec.EXACTLY));
mMapView.layout(0, 0, mMapWidth, mMapHeight);
googleMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
@Override
public void onMapLoaded() {
mMapView.setDrawingCacheEnabled(true);
mMapView.measure(View.MeasureSpec.makeMeasureSpec(mMapWidth, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(mMapHeight, View.MeasureSpec.EXACTLY));
mMapView.layout(0, 0, mMapWidth, mMapHeight);
mMapView.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(mMapView.getDrawingCache());
mMapView.setDrawingCacheEnabled(false);
mImageView.setImageBitmap(b);
}
});
}
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bundle mapViewBundle = outState.getBundle(MAP_VIEW_BUNDLE_KEY);
if (mapViewBundle == null) {
mapViewBundle = new Bundle();
outState.putBundle(MAP_VIEW_BUNDLE_KEY, mapViewBundle);
}
}
}
和activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="{PACKAGE_NAME}.MainActivity">
<ImageView
android:id="@+id/image_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</RelativeLayout>
在地图上用标记获取屏幕截图:
如果您希望在精简模式地图上显示我的位置点并使用默认位置来源,则需要致电onResume()
和onPause()
:
...
@Override
protected void onResume() {
super.onResume();
if (mMapView != null) {
mMapView.onResume();
}
}
@Override
protected void onPause() {
if (mMapView != null) {
mMapView.onPause();
}
super.onPause();
}
...
因为位置来源只会更新How to add a named vector as a row to a data frame。