上一讲我们介绍了如何在Activity中显示百度地图,很多情况下我们都需要在百度地图上显示当前位置。百度地图Android SDK更新到2.0之后,将定位功能进行了剥离,但它依旧保留了定位图层,方便开发者便捷的展示定位结果等信息。所以获取当前位置需要结合百度定位SDK使用。

1、添加定位sdk

所先在官方相关下载中下载最新的库文件。然后将liblocSDK3.so文件拷贝到libs/armeabi目录下。将locSDK3.3.jar文件拷贝到工程的libs目录下,并在工程属性-> Java Build Path-> Libraries中选择”Add JARs”,选定locSDK3.3.jar,确定后返回。现在我们工程的libs目录应该是这个样子:

BaiduMap-local
BaiduMap-local

2、设置AndroidManifest.xml

在application标签中声明service组件。

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

并声明使用权限

<!-- 使用定位功能所需权限 -->
 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 <permission android:name="android.permission.BAIDU_LOCATION_SERVICE"/>
 <uses-permission android:name="android.permission.BAIDU_LOCATION_SERVICE"/>
 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
 <uses-permission android:name="android.permission.ACCES_MOCK_LOCATION"/>
 <uses-permission android:name="android.permission.ACCESS_GPS"/>

3、新建相关Activity关实现代码

新建一个类ShowMyLocationActivity继承至Activity,并在AndroidManifest.xml注册。相关代码如下:

package com.liuzhichao.baidumapdemo;

import android.app.Activity;
import android.os.Bundle;
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.platform.comapi.basestruct.GeoPoint;

/**
 * 在百度地图上显示当前位置
 * @author liuzc
 * @url    http://liuzhichao.com
 * @mail   liuzc89@gmail.com
 */
public class ShowMyLocationActivity extends Activity{

	private LocationClient mLocationClient;
	private BDLocationListener myListener;
	private MapView mMapView;
	private MapController mMapController = null;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_map);

		//初始化百度地图
		initMapView();

		//初始化LocationClient类,推荐用getApplicationConext获取全进程有效的context
		mLocationClient = new LocationClient(getApplicationContext());

		//定位相关设置
		setLocOption(mLocationClient);

		//定位回调函数
		myListener = new MyLocationListenner();

		//注册监听函数
		mLocationClient.registerLocationListener(myListener);

		//开启定位
		mLocationClient.start();

		System.out.println("start----mLocationClient.isStarted:"+mLocationClient.isStarted());
	}

	//初始化百度地图
	private void initMapView() {
		mMapView = (MapView) findViewById(R.id.bmapsView);
		mMapController = mMapView.getController();
		mMapController.setZoom(14);
	}

	//设置定位参数包括:定位模式(单次定位,定时定位),返回坐标类型,是否打开GPS等等
	private void setLocOption(LocationClient mLocClient){
		LocationClientOption option = new LocationClientOption();
		option.setOpenGps(true); //是否打开gps
		option.setAddrType("all");//设置是否要返回地址信息,String 值为 all时,表示返回地址信息。其他值都表示不返回地址信息。
		option.setCoorType("bd09ll");//返回的定位结果是百度经纬度,默认值gcj02

		//当所设的整数值大于等于1000(ms)时,定位SDK内部使用定时定位模式。调用requestLocation( )后,每隔设定的时间,定位SDK就会进行一次定位。
		//当不设此项,或者所设的整数值小于1000(ms)时,采用一次定位模式。
		option.setScanSpan(1000);//设置发起定位请求的间隔时间为5000ms

		option.disableCache(true);//true表示禁用缓存定位,false表示启用缓存定位。
		option.setPoiNumber(5);	//最多返回POI个数
		option.setPoiDistance(1000); //poi查询距离		
		option.setPoiExtraInfo(true); //是否需要POI的电话和地址等详细信息		

		mLocClient.setLocOption(option);
	}

	public class MyLocationListenner implements BDLocationListener{

		@Override
		public void onReceiveLocation(BDLocation location) {
			if (location==null) {
				Toast.makeText(getApplicationContext(), "获取位置信息失败", Toast.LENGTH_LONG).show();
				return;
			}
			Toast.makeText(getApplicationContext(), "定位成功:"+location.getAddrStr(), Toast.LENGTH_LONG).show();
			showMyLocationOnMap(location.getLatitude(), location.getLongitude());
		}

		@Override
		public void onReceivePoi(BDLocation location) {

		}
	}

	/**
	 * 根据传入的经纬度在地图上显示
	 * @param latitude
	 * @param longitude
	 */
	private void showMyLocationOnMap(double latitude,double longitude){
		MyLocationOverlay myLocationOverlay = new MyLocationOverlay(mMapView);
		LocationData locData = new LocationData();
		locData.latitude = latitude;
		locData.longitude = longitude;
		locData.direction = 2.0f;
		myLocationOverlay.setData(locData);
		mMapView.getOverlays().add(myLocationOverlay);
		mMapView.refresh();
		mMapController.animateTo(new GeoPoint((int)(locData.latitude*1e6),(int)(locData.longitude* 1e6)));

		//定位成功后关闭定位
		mLocationClient.stop();

		//取消监听函数。
		mLocationClient.unRegisterLocationListener(myListener);

		System.out.println("stop----mLocationClient.isStarted:"+mLocationClient.isStarted());
	}

}

4、在MainActivity中添加到该类的”导航”:

public class MainActivity extends ListActivity {

	private Context context;
	 private String[] demos={"1、显示百度地图","2、在百度地图上显示当前位置"};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		context = this;
		setListAdapter(new ArrayAdapter <String> (this, android.R.layout.simple_list_item_1,demos));

		getListView().setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView <?>  parent, View view,
					int position, long id) {
				Intent intent = null;

				switch (position) {
				case 0:
					intent = new Intent(context, ShowMapActivity.class);
					break;
				case 1:
					intent = new Intent(context,ShowMyLocationActivity.class);
					break;
				default:
					break;
				}

				if (intent!=null) {
					startActivity(intent);
				}
			}
		});
	}
}

运行程序并点击”在百度地图上显示当前位置”,运行结果如下:

BaiduMap-local3
BaiduMap-local3

BaiduMap-local4
BaiduMap-local4

可以看出已经在地图上正确的显示了当前位置,但是存在一些比较怪异的地方:

1、我们并没有发送定位请求(并没有调用mLocationClient.requestLocation(或mLocationClient.requestPoi())就开始了定位。

2、仔细观察代码中两处关于mLocationClient.isStarted的打印信息,我们发现在调用mLocationClient.start()后,mLocationClient.isStarted返回的是false,而在调用mLocationClient.stop()后,mLocationClient.isStarted返回的反而是true;

BaiduMap-local2
BaiduMap-local2

所以下面的代码反而是错误的:

  if (mLocationClient!=null &amp;&amp; mLocationClient.isStarted()) {
			mLocationClient.requestLocation();
		}else{
			Toast.makeText(this, "定位失败", Toast.LENGTH_LONG).show();
		}

你会发现mLocationClient.requestLocation()并不会执行,而是显示”定位失败”。这时如果你没有调用mLocationClient.start(),则不能正常定位。所以我在想,是不是在调用mLocationClient.start()的时候,就开始定位了?但是这样的话,mLocationClient.requestLocation()或mLocationClient.requestPoi(),还有离线定位mLocationClient.requestOfflineLocation(),还有什么意义呢?

不过我们仍然是可以区分的,因为调用mLocationClient.requestPoi()的时候,返回的结果是在回调接口中的onReceivePoi()中处理。调用离线定位mLocationClient.requestOfflineLocation()时,返回结果虽然也是在回调接口中的onReceiveLocation()中,我们可以使用如下方法判断是否是离线定位请求:

@Override
		public void onReceiveLocation(BDLocation location) {
			if (location==null) {
				Toast.makeText(getApplicationContext(), "获取位置信息失败", Toast.LENGTH_LONG).show();
				return;
			}

			if (location.getLocType()==BDLocation.TypeOffLineLocation ) {
				//离线定位请求返回的定位结果
			}

		}

关于定位的更多信息请参考:百度定位Android API类参考3.3