莫名Crash---目睹Baidu地图API之怪现象一

原创 2013年12月06日 11:12:38

这是地图API系列的第一弹,那么首先从我经历的地图API说起。

几年前有过一次探索Google Map的经历,但是并没有深入和坚持下去。记得当时只是做一个可以定位和显示地图的Demo。

记得常用的几个类分别是MapView, MapController, Overlay, GeoPoint...


几年之后,国内的Android地图API也雨后春笋一样,遍地开花。

我心里觉得两个不错的代表就是Baidu地图和高德地图。

用朋友的话说,Baidu是家大公司,它出的API一定差不了。确实,Android版的百度地图,使用起来确实很棒,而且功能也越来越多,用起来也很容易上手。

而高德一直就是做导航的,也是Google的地图提供商之一。所以一直对其有着好感。


这一次,是要快速做一个原型Demo,提供的功能是在地图中显示当前的位置。说白了,就是和google地图那个demo类似,定位和显示地图。

首先用Baidu地图API打头阵。Baidu将Map和Location分开成两个SDK,这样每个都可以单独使用。后来发现,高德地图也是如此。

看了一阵API文档, 感到不明觉厉啊。

整体上看,共8个包。而其中最重要的(我按照自己需求而定)是:

com.baidu.mapapi.map        地图图层相关,包括地图控制,图层上自定义图标、图形等
com.baidu.mapapi.search    信息查询和路径规划相关

而常见的那些类(上述google地图中的)在这里都可以看到。这反映了同一领域的知识是相通的,看了高德的api更是如此感慨。


为了实现我想要的功能,只需将BaiduMapsApiDemo中的LocationOverlayDemo单独抽出来就可以。但我还是喜欢一切自己从头开始。

按照开发指南 中的Hello world开始,一步一步加入MyLocationOverlay等内容。其实一切是非常简单的,代码我就不列出了。

但是编译、手机中运行。App 死掉了!很干脆的死掉了。我从log里根本找不到一丝线索。

也许是我在加载地图和定位so和jar时出错了?

再按照文档一步一步重来,还是挂掉。浪费几个小时无果后,决定不能这样了。快速建立原型的宗旨是,要快速要出一个可以运行的程序。

好吧,直接在官方demo上修改吧。

一路重构下来,最后demo中只剩下LocationOverlayDemo和DemoApplication了。

我发现LocationOverlayDemo类中还有可重构的余地,比如这个类我没有必要使用的:

class MyLocationMapView extends MapView{
	static PopupOverlay   pop  = null;//弹出泡泡图层,点击图标使用
	public MyLocationMapView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}
	public MyLocationMapView(Context context, AttributeSet attrs){
		super(context,attrs);
	}
	public MyLocationMapView(Context context, AttributeSet attrs, int defStyle){
		super(context, attrs, defStyle);
	}
	@Override
    public boolean onTouchEvent(MotionEvent event){
		if (!super.onTouchEvent(event)){
			//消隐泡泡
			if (pop != null && event.getAction() == MotionEvent.ACTION_UP)
				pop.hidePop();
		}
		return true;
	}
}
因为现在没有对pop使用的需求,那么直接使用MapView就可以的,没有必要自己写这个类。

将程序中的MyLocationMapView替换为MapView,从常识上讲,这是可行的。但是编译、运行后,程序又挂了,跟之前的现象一样。

这次我没有着急,肯定是重构出问题了,而问题的root cause就是这个MyLocationMapView。

反复调试,我发现这么个怪现象:

只要我的地图包下有这样一个类继承自MapView,那么程序就不会Crash。下面是修改字官方Demo的源码,十分奇怪的源码:

package baidumapsdk.demo;

import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.map.LocationData;
import com.baidu.mapapi.map.MapController;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationOverlay;
import com.baidu.mapapi.map.MyLocationOverlay.LocationMode;
import com.baidu.mapapi.map.PopupClickListener;
import com.baidu.mapapi.map.PopupOverlay;
import com.baidu.platform.comapi.basestruct.GeoPoint;
/**
 * 此demo用来展示如何结合定位SDK实现定位,并使用MyLocationOverlay绘制定位位置
 * 同时展示如何使用自定义图标绘制并点击时弹出泡泡
 *
 */
public class LocationOverlayDemo extends Activity {
	private enum E_BUTTON_TYPE {
		LOC,
		COMPASS,
		FOLLOW
	}
	
	private E_BUTTON_TYPE mCurBtnType;

	// 定位相关
	LocationClient mLocClient;
	LocationData locData = null;
	public MyLocationListenner myListener = new MyLocationListenner();
	
	//定位图层
	locationOverlay myLocationOverlay = null;
	//弹出泡泡图层
	private PopupOverlay   pop  = null;//弹出泡泡图层,浏览节点时使用
	private TextView  popupText = null;//泡泡view
	private View viewCache = null;
	
	//地图相关,使用继承MapView的MyLocationMapView目的是重写touch事件实现泡泡处理
	//如果不处理touch事件,则无需继承,直接使用MapView即可
//	MyLocationMapView mMapView = null;	// 地图View
	MapView mMapView = null;	// 地图View
	private MapController mMapController = null;

	//UI相关
	OnCheckedChangeListener radioButtonListener = null;
	Button requestLocButton = null;
	boolean isRequest = false;//是否手动触发请求定位
	boolean isFirstLoc = true;//是否首次定位
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_locationoverlay);
        CharSequence titleLable="定位功能";
        setTitle(titleLable);
        requestLocButton = (Button)findViewById(R.id.button1);
        mCurBtnType = E_BUTTON_TYPE.LOC;
        OnClickListener btnClickListener = new OnClickListener() {
        	public void onClick(View v) {
				switch (mCurBtnType) {
				case LOC:
					//手动定位请求
					requestLocClick();
					break;
				case COMPASS:
					myLocationOverlay.setLocationMode(LocationMode.NORMAL);
					requestLocButton.setText("定位");
					mCurBtnType = E_BUTTON_TYPE.LOC;
					break;
				case FOLLOW:
					myLocationOverlay.setLocationMode(LocationMode.COMPASS);
					requestLocButton.setText("罗盘");
					mCurBtnType = E_BUTTON_TYPE.COMPASS;
					break;
				}
			}
		};
	    requestLocButton.setOnClickListener(btnClickListener);
	    
        RadioGroup group = (RadioGroup)this.findViewById(R.id.radioGroup);
        radioButtonListener = new OnCheckedChangeListener() {
			
			@Override
			public void onCheckedChanged(RadioGroup group, int checkedId) {
				if (checkedId == R.id.defaulticon){
					//传入null则,恢复默认图标
					modifyLocationOverlayIcon(null);
				}
				if (checkedId == R.id.customicon){
					//修改为自定义marker
					modifyLocationOverlayIcon(getResources().getDrawable(R.drawable.icon_geo));
				}
			}
		};
		group.setOnCheckedChangeListener(radioButtonListener);
        
		//地图初始化
//        mMapView = (MyLocationMapView)findViewById(R.id.bmapView);
		mMapView = (MapView)findViewById(R.id.bmapView);
        mMapController = mMapView.getController();
        mMapView.getController().setZoom(14);
        mMapView.getController().enableClick(true);
        mMapView.setBuiltInZoomControls(true);
      //创建 弹出泡泡图层
        createPaopao();
        
        //定位初始化
        mLocClient = new LocationClient( this );
        locData = new LocationData();
        mLocClient.registerLocationListener( myListener );
        LocationClientOption option = new LocationClientOption();
        option.setOpenGps(true);//打开gps
        option.setCoorType("bd09ll");     //设置坐标类型
        option.setScanSpan(1000);
        mLocClient.setLocOption(option);
        mLocClient.start();
       
        //定位图层初始化
		myLocationOverlay = new locationOverlay(mMapView);
		//设置定位数据
	    myLocationOverlay.setData(locData);
	    //添加定位图层
		mMapView.getOverlays().add(myLocationOverlay);
		myLocationOverlay.enableCompass();
		//修改定位数据后刷新图层生效
		mMapView.refresh();
		
    }
    /**
     * 手动触发一次定位请求
     */
    public void requestLocClick(){
    	isRequest = true;
        mLocClient.requestLocation();
        Toast.makeText(LocationOverlayDemo.this, "正在定位……", Toast.LENGTH_SHORT).show();
    }
    /**
     * 修改位置图标
     * @param marker
     */
    public void modifyLocationOverlayIcon(Drawable marker){
    	//当传入marker为null时,使用默认图标绘制
    	myLocationOverlay.setMarker(marker);
    	//修改图层,需要刷新MapView生效
    	mMapView.refresh();
    }
    /**
	 * 创建弹出泡泡图层
	 */
	public void createPaopao(){
		viewCache = getLayoutInflater().inflate(R.layout.custom_text_view, null);
        popupText =(TextView) viewCache.findViewById(R.id.textcache);
        //泡泡点击响应回调
        PopupClickListener popListener = new PopupClickListener(){
			@Override
			public void onClickedPopup(int index) {
				Log.v("click", "clickapoapo");
			}
        };
        pop = new PopupOverlay(mMapView,popListener);
//        MyLocationMapView.pop = pop;
	}
	/**
     * 定位SDK监听函数
     */
    public class MyLocationListenner implements BDLocationListener {
    	
        @Override
        public void onReceiveLocation(BDLocation location) {
            if (location == null)
                return ;
            
            locData.latitude = location.getLatitude();
            locData.longitude = location.getLongitude();
            //如果不显示定位精度圈,将accuracy赋值为0即可
            locData.accuracy = location.getRadius();
            // 此处可以设置 locData的方向信息, 如果定位 SDK 未返回方向信息,用户可以自己实现罗盘功能添加方向信息。
            locData.direction = location.getDerect();
            //更新定位数据
            myLocationOverlay.setData(locData);
            //更新图层数据执行刷新后生效
            mMapView.refresh();
            //是手动触发请求或首次定位时,移动到定位点
            if (isRequest || isFirstLoc){
            	//移动地图到定位点
            	Log.d("LocationOverlay", "receive location, animate to it");
                mMapController.animateTo(new GeoPoint((int)(locData.latitude* 1e6), (int)(locData.longitude *  1e6)));
                isRequest = false;
                myLocationOverlay.setLocationMode(LocationMode.FOLLOWING);
				requestLocButton.setText("跟随");
                mCurBtnType = E_BUTTON_TYPE.FOLLOW;
            }
            //首次定位完成
            isFirstLoc = false;
        }
        
        public void onReceivePoi(BDLocation poiLocation) {
            if (poiLocation == null){
                return ;
            }
        }
    }
    
    //继承MyLocationOverlay重写dispatchTap实现点击处理
  	public class locationOverlay extends MyLocationOverlay{

  		public locationOverlay(MapView mapView) {
  			super(mapView);
  			// TODO Auto-generated constructor stub
  		}
  		@Override
  		protected boolean dispatchTap() {
  			// TODO Auto-generated method stub
  			//处理点击事件,弹出泡泡
  			popupText.setBackgroundResource(R.drawable.popup);
			popupText.setText("我的位置");
			pop.showPopup(BMapUtil.getBitmapFromView(popupText),
					new GeoPoint((int)(locData.latitude*1e6), (int)(locData.longitude*1e6)),
					8);
  			return true;
  		}
  		
  	}

    @Override
    protected void onPause() {
        mMapView.onPause();
        super.onPause();
    }
    
    @Override
    protected void onResume() {
        mMapView.onResume();
        super.onResume();
    }
    
    @Override
    protected void onDestroy() {
    	//退出时销毁定位
        if (mLocClient != null)
            mLocClient.stop();
        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 boolean onCreateOptionsMenu(Menu menu) {
//        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}

class TestMapView extends MapView{
public TestMapView(Context context) {
	super(context);
	// TODO Auto-generated constructor stub
}
public TestMapView(Context context, AttributeSet attrs){
	super(context,attrs);
}
}

从代码中可以看出,TestMapView这个类我是根本没有用的,但是我删掉它,程序就会Crash。

好吧,我现在还是没有找到root cause,只能这样先用着。

大家也可以体验一样,并帮我找找原因。


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Android版百度地图MapView维护

最近项目工程使用百度地图,功能确实强大,但就像论坛里很多人提的那样,在MapView的刷新问题上,百度地图还有一定bug,比如在一个dialog中放一个MapView,却发现dialog中的MapVi...

解决百度地图找不到SDKInitializer,无法解析的问题

笔者根据网友的博客,在使用百度地图的时候导入jar与so文件,如图: 然后在jar已经导入的情况,出现了SDKInitializer无法解析的问题,也就是没有SDKInitializer这...

【Android开发】之Fragment重要函数讲解

上一节我们讲到了Fragment的生命周期(都是基于android.support.v4.app包下的Fragment),学习之后相信大家对它的生命周期有了很深入的了解了,如果还有不懂得,可以再看一下...

Android 嵌套布局简析

前言嵌套布局是事件分发的衍生内容,理解了嵌套布局的实现方式,Md的很多效果都是毛毛雨了原文地址进入Uml 时序图形 嵌套布局实现方式,以及 5.0 中与嵌套布局有关联的组件提起嵌套布局,MD中的 Co...

扭秧歌步法---目睹Baidu地图API之怪现象二

扭秧歌,已经冲出国门走向世界了。英文音译为“New Younger”! 它的步法特别有意思,就是走三歩而退一步。就好像无论走到哪都要回到原点一样。 非常巧的是,我在BaiduMapsApiDemo...

百度地图api android sdk leaked ServiceConnection com.baidu.location.LocationClient错误

最近在百度地图api 的android sdk , 下载了官方的例子运行,一切正常,然后参照定位图层写了个程序一运行,出现了以下错误: 03-29 15:36:52.300: E/Activit...

Baidu与Google地图API初探

前天周六,有个好友过来玩,他说想在他的网站中加入地图导航模块,但不知道选择哪个第三方Map API在网上查了下Baidu、Google、QQ和MapBar等4种Map API(都是采用JS开放API)...

百度地图 baidu map api应用

Summary:项目中需要使用百度地图来显示终端的位置。 1. 后台:获取存在数据库中的google gps地址,通过转换为baidu location,以json方式传到前端。 2. 前台:加载...

电脑上一些怪现象!!!!

  • 2009年10月26日 00:43
  • 1KB
  • 下载

ArcGIS API for JavaScript 地图加载空白现象-ArcGIS Web 开发学习(三)

我在做C#开发bs系统时,使用JavaScript加载了一个地图,但是加载完后出现了一个问题,就是map对象并没有布满整个mapdiv控件区域,参见下图:                     我明...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:莫名Crash---目睹Baidu地图API之怪现象一
举报原因:
原因补充:

(最多只允许输入30个字)