Android版百度地图MapView维护
最近项目工程使用百度地图,功能确实强大,但就像论坛里很多人提的那样,在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 } }按照这个方法修改代码后发现地图无论是在Dialog和Activity中都能正常使用,刷新问题不复存在。
由于我们看不到onResume和onPause中的源码,因此对于这个刷新问题,我们只能做猜测,我个人觉得MapView中有些刷新和显示上的控制是在onResume中操作,而在onPause中去暂停操作,个人觉得绘制地图应该是很耗资源的事情,所以确实需要这样的一些操作。但可能有些操作可能是静态全局性的,所以不管一个工程中有多少个MapView,都有些共用的操作,因此才会导致不同地图的刷新问题似乎会相互影响。
经过几天研究,我个人觉得目前的解决方案是每个MapView要有单独维护的onResume和onPause调用,不管这个MapView是在Dialog还是Activity中显示,在你需要使用MapView就调用其onResume方法,在你暂时不需要使用的时候就调用其onPause方法。
- 01-11全球最受赞誉公司揭晓:苹果连续九年第一
- 12-09罗伯特·莫里斯:让黑客真正变黑
- 12-09谁闯入了中国网络?揭秘美国绝密黑客小组TA
- 12-09警示:iOS6 惊现“闪退”BUG
- 11-18LG新能源宣布与Bear Robotics达成合作,成为
- 11-18机构:三季度全球个人智能音频设备市场强势
- 11-18闲鱼:注册用户过6亿 AI技术已应用于闲置交
- 11-18美柚、宝宝树回应“涉黄短信骚扰”:未发现
- 11-01京东七鲜与前置仓完成融合