最近项目工程使用百度地图,功能确实强大,但就像论坛里很多人提的那样,在MapView的刷新问题上,百度地图还有一定bug,比如在一个dialog中放一个MapView,却发现dialog中的MapView展现效果很差,很多地图上的标志没有刷新出来。比如下图:
我们可以看到整个地图完全乱套了,现在我贴在这个dialog的代码,然后一起分析下问题。
- package baidumapsdk.demo;
- import android.app.Dialog;
- import android.content.Context;
- import android.view.View;
- import android.view.Window;
- import android.widget.Button;
- import com.baidu.mapapi.map.MapView;
- import com.baidu.platform.comapi.basestruct.GeoPoint;
- public class MapDialog extends Dialog{
- /**
- * MapView 是地图主控件
- */
- private MapView mMapView = null;
- private Button mBtnBack = null;
- public MapDialog(Context context) {
- super(context);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.mapdialog);
- mMapView = (MapView)findViewById(R.id.bmapView);
- mMapView.setBuiltInZoomControls(true);
- mMapView.getController().setCenter(new GeoPoint((int)(39.945 * 1E6), (int)(116.404 * 1E6)));
- mBtnBack = (Button)findViewById(R.id.btn_back);
- mBtnBack.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- dismiss();
- }
- });
- }
- @Override
- public void dismiss() {
- super.dismiss();
- }
- }
我们看到在Dialog中我们就直接从xml中引用了地图,不过在百度地图Hello World 介绍中,百度地图似乎还调动了MapView的onResume和onPause等方法,虽然它们都是在Activity中调用的,而我们这是Dialog,但没有条件我们可以创造条件调用,直接在构造函数里调用onResume,dismiss()里调用onPause。
- package baidumapsdk.demo;
- import android.app.Dialog;
- import android.content.Context;
- import android.view.View;
- import android.view.Window;
- import android.widget.Button;
- import com.baidu.mapapi.map.MapView;
- import com.baidu.platform.comapi.basestruct.GeoPoint;
- public class MapDialog extends Dialog{
- /**
- * MapView 是地图主控件
- */
- private MapView mMapView = null;
- private Button mBtnBack = null;
- public MapDialog(Context context) {
- super(context);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.mapdialog);
- mMapView = (MapView)findViewById(R.id.bmapView);
- mMapView.setBuiltInZoomControls(true);
- mMapView.onResume();
- mMapView.getController().setCenter(new GeoPoint((int)(39.945 * 1E6), (int)(116.404 * 1E6)));
- mBtnBack = (Button)findViewById(R.id.btn_back);
- mBtnBack.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- dismiss();
- }
- });
- }
- @Override
- public void dismiss() {
- mMapView.onPause();
- super.dismiss();
- }
- }
这个时候似乎我们的使用有效果了,这样使用方式Dialog中MapView刷新没有问题了。
但是新问题来了。我们Dialog一般都是在Activity中调用的,如果调用的Activity中也有MapView。
- package baidumapsdk.demo;
- import android.app.Activity;
- import android.content.Intent;
- import android.graphics.Bitmap;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.Toast;
- import com.baidu.mapapi.BMapManager;
- import com.baidu.mapapi.map.MKMapViewListener;
- import com.baidu.mapapi.map.MKOfflineMap;
- import com.baidu.mapapi.map.MKOfflineMapListener;
- import com.baidu.mapapi.map.MapController;
- import com.baidu.mapapi.map.MapPoi;
- import com.baidu.mapapi.map.MapView;
- import com.baidu.platform.comapi.basestruct.GeoPoint;
- /**
- * 演示MapView的基本用法
- */
- public class BaseMapDemo extends Activity implements MKOfflineMapListener{
- final static String TAG = "MainActivity";
- /**
- * MapView 是地图主控件
- */
- private MapView mMapView = null;
- /**
- * 用MapController完成地图控制
- */
- private MapController mMapController = null;
- private Button mBtnDialog = null;
- private Button mBtnActivity = null;
- private MKOfflineMap mOffline = null;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- /**
- * 使用地图sdk前需先初始化BMapManager.
- * BMapManager是全局的,可为多个MapView共用,它需要地图模块创建前创建,
- * 并在地图地图模块销毁后销毁,只要还有地图模块在使用,BMapManager就不应该销毁。
- */
- DemoApplication app = (DemoApplication)this.getApplication();
- if (app.mBMapManager == null) {
- app.mBMapManager = new BMapManager(this);
- /**
- * 如果BMapManager没有初始化则初始化BMapManager
- */
- app.mBMapManager.init(DemoApplication.strKey,new DemoApplication.MyGeneralListener());
- }
- /**
- * 由于MapView在setContentView()中初始化,所以它需要在BMapManager初始化之后
- */
- setContentView(R.layout.activity_main);
- mMapView = (MapView)findViewById(R.id.bmapView);
- mMapView.setBuiltInZoomControls(true);
- /**
- * 获取地图控制器
- */
- mMapController = mMapView.getController();
- /**
- * 设置地图是否响应点击事件 .
- */
- mMapController.enableClick(true);
- /**
- * 设置地图缩放级别
- */
- mMapController.setZoom(12);
- /**
- * 将地图移动至指定点
- * 使用百度经纬度坐标,可以通过http://api.map.baidu.com/lbsapi/getpoint/index.html查询地理坐标。
- * 如果需要在百度地图上显示使用其他坐标系统的位置,请发邮件至mapapi@baidu.com申请坐标转换接口。
- */
- GeoPoint p ;
- double cLat = 39.945 ;
- double cLon = 116.404 ;
- Intent intent = getIntent();
- if ( intent.hasExtra("x") && intent.hasExtra("y") ){
- //当用intent参数时,设置中心点为指定点
- Bundle b = intent.getExtras();
- p = new GeoPoint(b.getInt("y"), b.getInt("x"));
- }else{
- //设置中心点为天安门
- p = new GeoPoint((int)(cLat * 1E6), (int)(cLon * 1E6));
- }
- mMapController.setCenter(p);
- mOffline = new MKOfflineMap();
- /**
- * 初始化离线地图模块,MapControler可从MapView.getController()获取
- */
- mOffline.init(mMapController, this);
- // mOffline.scan();
- mBtnActivity = (Button)findViewById(R.id.btn_activity);
- mBtnDialog = (Button)findViewById(R.id.btn_dialog);
- mBtnActivity.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent = new Intent(BaseMapDemo.this, GeometryDemo.class);
- startActivity(intent);
- }
- });
- mBtnDialog.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- MapDialog dialog = new MapDialog(BaseMapDemo.this);
- dialog.show();
- }
- });
- }
- @Override
- protected void onPause() {
- /**
- * MapView的生命周期与Activity同步,当activity挂起时需调用MapView.onPause() 。
- */
- mMapView.onPause();
- super.onPause();
- }
- @Override
- protected void onResume() {
- /**
- * MapView的生命周期与Activity同步,当activity恢复时需调用MapView.onResume() 。
- */
- mMapView.onResume();
- super.onResume();
- }
- @Override
- protected void onDestroy() {
- /**
- * MapView的生命周期与Activity同步,当activity销毁时需调用MapView.destroy() 。
- */
- mMapView.destroy();
- super.onDestroy();
- }
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- mMapView.onSaveInstanceState(outState);
- }
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- mMapView.onRestoreInstanceState(savedInstanceState);
- }
- @Override
- public void onGetOfflineMapState(int arg0, int arg1) {
- // TODO Auto-generated method stub
- }
- }
这个Activity的中使用MapView的方式就是百度官方代码使用MapView的方式,当我们dimiss了dialog,发现Activity上的MapView的刷新也出问题了,甚至我测试有的时候Activity上的MapView连动都不能动,整个屏幕像死机了一样。
而且刷新混乱的方式跟之前Dialog混乱的方式很像,之前我们解决Dialog刷新混乱的问题的时候,是在Dialog调用了MapView的onResume方法,现在我们也来在dismiss了Dialog后再次调用Activity中MapView的onResume,有onResume方法就得有相应的onPause方法对应,显然,是在show Dialog的时候让Activity中的MapView onPause。
现在我们把Dialog和Activity中代码修改如下:
- package baidumapsdk.demo;
- import android.app.Dialog;
- import android.content.Context;
- import android.view.View;
- import android.view.Window;
- import android.widget.Button;
- import baidumapsdk.demo.BaseMapDemo.MapDialogCallback;
- import com.baidu.mapapi.map.MapView;
- import com.baidu.platform.comapi.basestruct.GeoPoint;
- public class MapDialog extends Dialog{
- /**
- * MapView 是地图主控件
- */
- private MapView mMapView = null;
- private Button mBtnBack = null;
- private MapDialogCallback mCallback;
- public MapDialog(Context context) {
- super(context);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.mapdialog);
- mMapView = (MapView)findViewById(R.id.bmapView);
- mMapView.setBuiltInZoomControls(true);
- mMapView.onResume();
- mMapView.getController().setCenter(new GeoPoint((int)(39.945 * 1E6), (int)(116.404 * 1E6)));
- mBtnBack = (Button)findViewById(R.id.btn_back);
- mBtnBack.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- dismiss();
- }
- });
- }
- @Override
- public void dismiss() {
- mMapView.onPause();
- mCallback.mapback();
- super.dismiss();
- }
- public void registerCallback(MapDialogCallback callback) {
- mCallback = callback;
- }
- }
- package baidumapsdk.demo;
- import android.app.Activity;
- import android.content.Intent;
- import android.graphics.Bitmap;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.Toast;
- import com.baidu.mapapi.BMapManager;
- import com.baidu.mapapi.map.MKMapViewListener;
- import com.baidu.mapapi.map.MKOfflineMap;
- import com.baidu.mapapi.map.MKOfflineMapListener;
- import com.baidu.mapapi.map.MapController;
- import com.baidu.mapapi.map.MapPoi;
- import com.baidu.mapapi.map.MapView;
- import com.baidu.platform.comapi.basestruct.GeoPoint;
- /**
- * 演示MapView的基本用法
- */
- public class BaseMapDemo extends Activity implements MKOfflineMapListener{
- final static String TAG = "MainActivity";
- /**
- * MapView 是地图主控件
- */
- private MapView mMapView = null;
- /**
- * 用MapController完成地图控制
- */
- private MapController mMapController = null;
- private Button mBtnDialog = null;
- private Button mBtnActivity = null;
- private MKOfflineMap mOffline = null;
- public interface MapDialogCallback{
- void mapback();
- }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- /**
- * 使用地图sdk前需先初始化BMapManager.
- * BMapManager是全局的,可为多个MapView共用,它需要地图模块创建前创建,
- * 并在地图地图模块销毁后销毁,只要还有地图模块在使用,BMapManager就不应该销毁。
- */
- DemoApplication app = (DemoApplication)this.getApplication();
- if (app.mBMapManager == null) {
- app.mBMapManager = new BMapManager(this);
- /**
- * 如果BMapManager没有初始化则初始化BMapManager
- */
- app.mBMapManager.init(DemoApplication.strKey,new DemoApplication.MyGeneralListener());
- }
- /**
- * 由于MapView在setContentView()中初始化,所以它需要在BMapManager初始化之后。
- */
- setContentView(R.layout.activity_main);
- mMapView = (MapView)findViewById(R.id.bmapView);
- mMapView.setBuiltInZoomControls(true);
- /**
- * 获取地图控制器
- */
- mMapController = mMapView.getController();
- /**
- * 设置地图是否响应点击事件
- */
- mMapController.enableClick(true);
- /**
- * 设置地图缩放级别
- */
- mMapController.setZoom(12);
- /**
- * 将地图移动至指定点
- * 使用百度经纬度坐标,可以通过http://api.map.baidu.com/lbsapi/getpoint/index.html查询地理坐标
- * 如果需要在百度地图上显示使用其他坐标系统的位置,请发邮件至mapapi@baidu.com申请坐标转换接口。
- */
- GeoPoint p ;
- double cLat = 39.945 ;
- double cLon = 116.404 ;
- Intent intent = getIntent();
- if ( intent.hasExtra("x") && intent.hasExtra("y") ){
- //当用intent参数时,设置中心点为指定点。
- Bundle b = intent.getExtras();
- p = new GeoPoint(b.getInt("y"), b.getInt("x"));
- }else{
- //设置中心点为天安门
- p = new GeoPoint((int)(cLat * 1E6), (int)(cLon * 1E6));
- }
- mMapController.setCenter(p);
- mOffline = new MKOfflineMap();
- /**
- * 初始化离线地图模块,MapControler可从MapView.getController()获取。
- */
- mOffline.init(mMapController, this);
- // mOffline.scan();
- mBtnActivity = (Button)findViewById(R.id.btn_activity);
- mBtnDialog = (Button)findViewById(R.id.btn_dialog);
- mBtnActivity.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent = new Intent(BaseMapDemo.this, GeometryDemo.class);
- startActivity(intent);
- }
- });
- mBtnDialog.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- mMapView.onPause();
- MapDialog dialog = new MapDialog(BaseMapDemo.this);
- dialog.registerCallback(new MapDialogCallback() {
- @Override
- public void mapback() {
- // TODO Auto-generated method stub
- mMapView.onResume();
- }
- });
- dialog.show();
- }
- });
- }
- @Override
- protected void onPause() {
- /**
- * MapView的生命周期与Activity同步,当activity挂起时需调用MapView.onPause() 。
- */
- mMapView.onPause();
- super.onPause();
- }
- @Override
- protected void onResume() {
- /**
- * MapView的生命周期与Activity同步,当activity恢复时需调用MapView.onResume() 。
- */
- mMapView.onResume();
- super.onResume();
- }
- @Override
- protected void onDestroy() {
- /**
- * MapView的生命周期与Activity同步,当activity销毁时需调用MapView.destroy() 。
- */
- mMapView.destroy();
- super.onDestroy();
- }
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- mMapView.onSaveInstanceState(outState);
- }
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- mMapView.onRestoreInstanceState(savedInstanceState);
- }
- @Override
- public void onGetOfflineMapState(int arg0, int arg1) {
- // TODO Auto-generated method stub
- }
- }
由于我们看不到onResume和onPause中的源码,因此对于这个刷新问题,我们只能做猜测,我个人觉得MapView中有些刷新和显示上的控制是在onResume中操作,而在onPause中去暂停操作,个人觉得绘制地图应该是很耗资源的事情,所以确实需要这样的一些操作。但可能有些操作可能是静态全局性的,所以不管一个工程中有多少个MapView,都有些共用的操作,因此才会导致不同地图的刷新问题似乎会相互影响。
经过几天研究,我个人觉得目前的解决方案是每个MapView要有单独维护的onResume和onPause调用,不管这个MapView是在Dialog还是Activity中显示,在你需要使用MapView就调用其onResume方法,在你暂时不需要使用的时候就调用其onPause方法。
本编博文的源码在 源码可以下载到。