百度地图开发初步

       上周学了了一下手机GPS定位以及百度地图的使用,现在对此做一个总结:

       个人感觉地图应用可以划分三个部分:首先是定位,可以是精度高但是速度稍慢的gps定位,也可以是速度快精度低移动网络的定位,这个完全由用户自己选择,定位方法会返回一个包含经度纬度速度方向等很多参数的一个 ”位置“ 。然后就是地图,虽然android提供了google地图但是无法使用,在国内就直接用百度地图吧,通过刚才刚才那个”位置“就可以定位到地图。最后一部分就是百度地图的其他服务功能了,比如附近,路线,导航等

     1.定位

     其实百度地图直接提供了定位api的,但我想先用android自带定位api试下android定位api下面有几个重要的类:LocationManager是一个管理类,对它可以调用getLastKnownLocation()手动得到当前定位,对它调用requestLocationUpdates()可以绑定监听,当位置或者手机状态改变触发。Location是位置的实体类,还有一个就是定位参数provider包括定位方式(gps还是net),精度,耗电量等等。最后就是一个监听LocationListener(),监听位置改变,gps状态改变等,具体实现是这样的:

    首先获得一个provider,就是定位参数:

private void getProvider(){
		// 查找到服务信息        
				Criteria criteria = new Criteria();        
				criteria.setAccuracy(Criteria.ACCURACY_FINE); // 高精度        
				criteria.setAltitudeRequired(false);        
				criteria.setBearingRequired(false);        
				criteria.setCostAllowed(true);        
				criteria.setPowerRequirement(Criteria.POWER_LOW); // 低功耗
				 provider = lm.getBestProvider(criteria, false); // 获取GPS信
				 
				 Toast.makeText(this, "当前工作的provider是: " + provider, 0)
.show();
	}

      这里就是返回一个最优方式系统选择,但有的文章说部分手机不支持getBestProvider(),那可以自己选择,就是根据用户是否开启gps和移动网络,来选择一个provider,当然gps应该优先,其实provider就是3个LocationManager的常量,接下我们可以干两件事:在onStart里面得到当前位置:

protected void onStart() {
		// TODO Auto-generated method stub
		super.onStart();
		Log.d("dml", "onStart......provider :" + provider);
		Location location2 = lm.getLastKnownLocation(provider);
		Location location = MapUtils.getNewLocation(location2); // 通过GPS获取位置 
//		 while(location  == null)
//		 {
//			 lm.requestLocationUpdates(provider, 3000, 8,listener);
//		   //mgr.requestLocationUpdates("gps", 60000, 1, locationListener);
//		 }

		if(location!=null){
			Toast.makeText(this, "当前经纬度: " + location.getLongitude() + ","
 + location.getLatitude(), 0).show();
			setMyPosition(location);
		}
		else{
			Log.d("dml", "getLastKnownLocation 返回null");
		}
	}

   这里有个方法叫getLastKnownLocation(), 是先判断上次 定位位置,如果gps或者net没有开启就返回上次位置,否则重新获得当前定位,相当于一个缓存吧。但 实际应用中经常返回null,网上给出的解决办法都一样:注册两个权限,把监听现在onCreate()里面实例化:

listener =  new LocationListener() {
			
			@Override
			public void onStatusChanged(String provider, int status, 
Bundle extras) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onProviderEnabled(String provider) {
				// TODO Auto-generated method stub
				Location location = MapUtils.getNewLocation
(lm.getLastKnownLocation(provider));
				 setMyPosition(location);
				Log.d("dml", "onProviderEnabled--------");
			}
			
			@Override
			public void onProviderDisabled(String provider) {
				// TODO Auto-generated method stub
				Log.d("dml", "onProviderDisabled--------");
			}
			
			@Override
			public void onLocationChanged(Location location) {
				// TODO Auto-generated method stub
				location = MapUtils.getNewLocation(location);
				Toast.makeText(MainActivity.this, "更新经纬度: 
" + location.getLongitude() + "," + location.getLatitude(), 0).show();
				 setMyPosition(location);
				Log.d("dml", "onLocationChanged--------");
			}
		};

     接上面说,干第二件事就是在onResume()绑定监听:

@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		lm.requestLocationUpdates(provider, 3000, 8,listener);
	}

      第一个参数就是刚才得到的provider,第二个参数是3000ms定位一次,8 m是精确距离,listener当然就是onCreate实例化的监听,一切准备完毕就可以在onLocationChanged()里面更新地图啦,也可以在地图上放一个按钮,用getLastKnownLocation()手动更新。


  2. 百度地图

      上面是用android系统自带api获取定位,但最终还是要显示在百度地图上,这里有两个问题:1.上面返回的位置是Location类型,BaiduMap的位置是BDLocation,不过其实就是获取精度这个方法不一样,我们改成Location自己的就OK   2. 用android自带api获得的定位显示在BaiduMap上面位置始终偏移1000M左右,这个不是精度问题而是地图不一样,我们用google api得到的位置放在BaiduMap需要算法纠正:

/** 
	 * 各地图API坐标系统比较与转换; 
	 * WGS84坐标系:即地球坐标系,国际上通用的坐标系。设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系, 
	 * 谷歌地图采用的是WGS84地理坐标系(中国范围除外); 
	 * GCJ02坐标系:即火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。 
	 * 谷歌中国地图和搜搜中国地图采用的是GCJ02地理坐标系; BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系; 
	 * 搜狗坐标系、图吧坐标系等,估计也是在GCJ02基础上加密而成的。 chenhua 
	 */  
	 /** 
     * 84 to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System 
     *  
     * @param lat 
     * @param lon 
     * @return 
     */  
    public static Gps gps84_To_Gcj02(double lat, double lon) {  
        if (outOfChina(lat, lon)) {  
            return null;  
        }  
        double dLat = transformLat(lon - 105.0, lat - 35.0);  
        double dLon = transformLon(lon - 105.0, lat - 35.0);  
        double radLat = lat / 180.0 * pi;  
        double magic = Math.sin(radLat);  
        magic = 1 - ee * magic * magic;  
        double sqrtMagic = Math.sqrt(magic);  
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);  
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);  
        double mgLat = lat + dLat;  
        double mgLon = lon + dLon;  
        return new Gps(mgLat, mgLon);  
    }
    
    /** 
     * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标 
     *  
     * @param gg_lat 
     * @param gg_lon 
     */  
    public static Gps gcj02_To_Bd09(double gg_lat, double gg_lon) {  
        double x = gg_lon, y = gg_lat;  
        double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi);  
        double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi);  
        double bd_lon = z * Math.cos(theta) + 0.0065;  
        double bd_lat = z * Math.sin(theta) + 0.006;  
        return new Gps(bd_lat, bd_lon);  
    } 
    
    public static Gps gps84_To_Bd09(double lat, double log){
    	Gps gps = gps84_To_Gcj02(lat,log);
    	return gcj02_To_Bd09(gps.getWgLat(),gps.getWgLon());
    }

        我要用的就是最后一个方法!

       这样折腾一番可以准确定位了,如果想简单一点就直接用BaiduMap提供的全套定位地图api吧。代码更简洁定位也更快,答题思路和上面差不多的,只不过不需要坐标转换了,而且这个定位其实是放入一个service更加合理,我们要在manifest注册一个service:

 <service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote"></service>

添加权限:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
	<uses-permission android:name="android.permission.GET_ACCOUNTS" />  
	<uses-permission android:name="android.permission.USE_CREDENTIALS" />  
	<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />  
	<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />  
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
	<uses-permission android:name="android.permission.INTERNET" />  
	<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />  
	<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />  
	<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />  
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
	<uses-permission android:name="android.permission.BROADCAST_STICKY" />  
	<uses-permission android:name="android.permission.WRITE_SETTINGS" />  
	<uses-permission android:name="android.permission.READ_PHONE_STATE" />

   在Aplication初始化 ,当然也要在manifest声明MyAplication

public class MyApplication extends Application {
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		SDKInitializer.initialize(this);  
	}
}

     核心代码,附带实现了一下点击我的位置弹出窗口显示位置:

public class BaiduActivity extends Activity {
    
    /** 
     * 定位SDK的核心类 
     */  
	public LocationClient mLocationClient = null;
	public BDLocationListener myListener = new MyLocationListener();
	private MapView mMapView;
	private BaiduMap mBaiduMap;
	private Button reqLocation;
	private BDLocation myLocation;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		mMapView = (MapView) findViewById(R.id.bmapView);
		reqLocation = (Button)findViewById(R.id.request);
		// 手动请求定位
		reqLocation.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Toast.makeText(BaiduActivity.this, MapUtils.getStr(BaiduActivity.this, R.string.is_locate), 0).show();
				if (mLocationClient != null && mLocationClient.isStarted())
					mLocationClient.requestLocation();
				else 
					Log.d("dml", "locClient is null or not started");
			}
		});
		mBaiduMap = mMapView.getMap();  
		//普通地图  
		mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
		mBaiduMap.setOnMyLocationClickListener(listener); 
		 mLocationClient = new LocationClient(getApplicationContext());     //声明LocationClient类
		 LocationClientOption option = new LocationClientOption();
		 option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);//设置定位模式 高精度
		 option.setCoorType("bd09ll");//返回的定位结果是百度经纬度,默认值gcj02
		 option.setScanSpan(5000);//设置发起定位请求的间隔时间为5000ms
		 option.setIsNeedAddress(true);//返回的定位结果包含地址信息
		 option.setNeedDeviceDirect(true);//返回的定位结果包含手机机头的方向
		 mLocationClient.setLocOption(option);
		 mLocationClient.registerLocationListener( myListener );    //注册监听函数
		 mLocationClient.start();  // 调用此方法开始定位  
	}
	
	private void setMyPosition(BDLocation location ){
		if(location==null){
			return;
		}
		// 开启定位图层  
		mBaiduMap.setMyLocationEnabled(true);  
		// 构造定位数据  
		MyLocationData locData = new MyLocationData.Builder()  
		    .accuracy(location.getRadius())  // 获取精度
		    // 此处设置开发者获取到的方向信息,顺时针0-360  
		    .direction(100).latitude(location.getLatitude())  
		    .longitude(location.getLongitude()).build();  
		// 设置定位数据  
		mBaiduMap.setMyLocationData(locData);  
		// 设置定位图层的配置(定位模式,是否允许方向信息,用户自定义定位图标)  
		BitmapDescriptor mCurrentMarker = BitmapDescriptorFactory  
		    .fromResource(R.drawable.position);  
		MyLocationConfiguration config = new MyLocationConfiguration(LocationMode.FOLLOWING, true, mCurrentMarker);  
		mBaiduMap.setMyLocationConfigeration(config); 
		
	}
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		//退出时销毁定位  
        if (mLocationClient != null){  
        	mLocationClient.stop();  
        }  
	}
	
	public class MyLocationListener implements BDLocationListener {
		@Override
		public void onReceiveLocation(BDLocation location) {
			if (location == null)
		            return ;
			
			myLocation = location;
			setMyPosition(location);
		}

		
	}
	
	OnMyLocationClickListener listener = new OnMyLocationClickListener() {  
	    /** 
	    * 地图定位图标点击事件监听函数 
	    */  
	    public boolean onMyLocationClick(){
	    	Log.d("dml", "点击 : 我的位置");
	    	//创建InfoWindow展示的view  
	    	Button button = new Button(getApplicationContext());
	    	button.setText(myLocation.getAddrStr());
	    	button.setLayoutParams(new LayoutParams(60, 20));
	    	button.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					// TODO Auto-generated method stub
					mBaiduMap.hideInfoWindow();
				}
			});
	    	//定义用于显示该InfoWindow的坐标点  
	    	double lon = myLocation.getLongitude();
	    	double la = myLocation.getLatitude();
	    	LatLng pt = new LatLng(la, lon);  
	    	//创建InfoWindow , 传入 view, 地理坐标, y 轴偏移量 
	    	InfoWindow mInfoWindow = new InfoWindow(button, pt, -47);  
	    	//显示InfoWindow  
	    	mBaiduMap.showInfoWindow(mInfoWindow);
	    	
	    	return false;
	    }  
	};
}

   3. 丰富的服务功能

    BaiduMap里面提供了巨多的类似附近,导航,路线等api,这个我暂时用不到先不做研究。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值