现在的位置: 首页 > 综合 > 正文

Android版百度地图MapView维护

2016年12月26日 ⁄ 综合 ⁄ 共 11422字 ⁄ 字号 评论关闭

最近项目工程使用百度地图,功能确实强大,但就像论坛里很多人提的那样,在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方法。

本编博文的源码在 源码可以下载到。

抱歉!评论已关闭.