您的位置:首页 > 移动开发 > Android开发

Android应用中使用百度地图API定位自己的位置(二)

2016-04-17 18:07 477 查看
官方文档:http://developer.baidu.com/map/sdkandev-6.htm#.E7.AE.80.E4.BB.8B3

百度地图SDK为开发人员们提供了例如以下类型的地图覆盖物:

我的位置图层(MyLocationOverlay):用于显示用户当前位置的图层(支持自己定义位置图标)。

Poi搜索结果图层(PoiOverlay):用于显示兴趣点搜索结果的图层;

路线图层(RouteOverlay):公交、步行和驾车线路图层,将公交、步行和驾车出行方案的路线及关键点显示在地图上(起、终点图标用户可自己定义)。

公交换乘图层(TransitOverlay):公交换乘线路图层。将某一特定地区的公交出行方案的路线及换乘位置显示在地图上(起、终点图标用户可自己定义);

自己定义图层(ItemizedOverlay):可将一个或多个兴趣点绘制到地图上,且支持自己定义图标(支持动态更新Item位置、图标);

弹出窗图层(PopupOverlay):在地图上显示一个弹出窗体;

几何图形绘制图层(GraphicsOverlay):用于绘制点、折线段、弧线、圆、矩形、多边形等几何图形的图层;

文字绘制图层(TextOverlay):用于绘制文字的图层。

图片图层(GroundOverlay):用于展示用户传入图片的图层。

全景图图层(PanoramaOverlay):在全景图内标绘兴趣点,支持自己定义图标样式。

注:除弹出窗图层外,其它各个图层均已实现多实例。全景图图层是针对全景图所使用的特殊图层。

MapView使用一个List管理覆盖物,通过向MapView.getOverlays() add或remove上述类或其基类的实例就可以向地图加入或删除覆盖物。在更新地图覆盖物后,需调用MapView.refresh() 使更新生效。

定位原理

使用百度Android定位SDK必须注冊GPS和网络使用权限。定位SDK採用GPS、基站、Wi-Fi信号进行定位。当应用程序向定位SDK发起定位请求时,定位SDK会根据应用的定位因素(GPS、基站、Wi-Fi信号)的实际情况(如是否开启GPS、是否连接网络、是否有信号等)来生成对应定位根据进行定位。

用户能够设置满足自身需求的定位根据:

若用户设置GPS优先。则优先使用GPS进行定位。假设GPS定位未打开或者没有可用位置信息。且网络连接正常,定位SDK则会返回网络定位(即Wi-Fi与基站)的最优结果。

为了使获得的网络定位结果更加精确。请打开手机的Wi-Fi开关。

以下我们将利用 MyLocationOverlay和
PopupOverlay 这两个类

一 . 导入库文件

在使用百度定位SDKv4.0之前。我们要下载最新的库文件,下载地址:点击下载相关库文件,将liblocSDK4.so文件复制到libs/armeabi文件夹下。将locSDK4.0.jar文件复制到project的libs文件夹下

文件夹结构例如以下:

库文件下载地址:http://pan.baidu.com/s/1ntNqKwp

二 . 布局文件,一个百度地图控件,加一个手动点击实现定位的button

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
/>
<Button
android:id="@+id/request"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="10dp"
android:layout_marginTop="10dip"
android:background="@drawable/mylocation"
/>

</RelativeLayout>


然后是主 Activity

package com.majianjie.baidumap;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.Button;
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.BMapManager;
import com.baidu.mapapi.MKGeneralListener;
import com.baidu.mapapi.map.LocationData;
import com.baidu.mapapi.map.MKEvent;
import com.baidu.mapapi.map.MKMapViewListener;
import com.baidu.mapapi.map.MapController;
import com.baidu.mapapi.map.MapPoi;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationOverlay;
import com.baidu.mapapi.map.PopupClickListener;
import com.baidu.mapapi.map.PopupOverlay;
import com.baidu.platform.comapi.basestruct.GeoPoint;
import com.example.baidumap.R;

public class MainActivity extends Activity {

//声明控件
private Button request;

private Toast mToast=null;
private BMapManager mBMapManager=null;
private MapView mMapView = null;			//MapView 是地图主控件
private MapController mMapController = null;//用MapController完毕地图控制

private LocationClient mLocClient;
public LocationData mLocData = null;

private LocationOverlay myLocationOverlay = null;//定位图层
private boolean isRequest = false;//是否手动触发请求定位
private boolean isFirstLoc = true;//是否首次定位

private PopupOverlay mPopupOverlay  = null;//弹出泡泡图层。浏览节点时使用
private View viewCache=null;
public BDLocation location = new BDLocation();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//**使用地图sdk前需先初始化BMapManager,这个必须在setContentView()先初始化
mBMapManager = new BMapManager(this);
//第一个參数是API key,   第二个參数是经常使用事件监听。用来处理通常的网络错误,授权验证错误等。你也能够不加入这个回调接口
mBMapManager.init("LDtH1sVwr7kygaF0aTqaVwWU", new MKGeneralListener() {
//授权错误的时候调用的回调函数
@Override
public void onGetPermissionState(int iError) {
if (iError ==  MKEvent.ERROR_PERMISSION_DENIED) {
showToast("API KEY错误, 请检查!

");
}
}
//一些网络状态的错误处理回调函数
@Override
public void onGetNetworkState(int iError) {
if (iError == MKEvent.ERROR_NETWORK_CONNECT) {
Toast.makeText(getApplication(), "您的网络出错啦!", Toast.LENGTH_LONG).show();
}
}
});
//初始化
init();
//单击事件
click();
}

//* 显示Toast消息
private void showToast(String msg){
if(mToast == null){
mToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
}else{
mToast.setText(msg);
mToast.setDuration(Toast.LENGTH_SHORT);
}
mToast.show();
}
private void click() {
request.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
requestLocation();
}
});

}
@Override
protected void onResume() {
//MapView的生命周期与Activity同步,当activity挂起时需调用MapView.onPause()
mMapView.onResume();
mBMapManager.start();//又一次启动
super.onResume();
}
@Override
protected void onPause() {
//MapView的生命周期与Activity同步。当activity挂起时需调用MapView.onPause()
mMapView.onPause();
super.onPause();
}

private void init() {
//使用自定义的title,注意顺序
setContentView(R.layout.activity_main);   //activity的布局                   //这里是加入自定义的titlebtn.xml

//通过id找到他们
mMapView = (com.baidu.mapapi.map.MapView) findViewById(R.id.bmapView);
mMapController=mMapView.getController(); //获取地图控制器
mMapController.enableClick(true);   //设置地图是否响应点击事件
request=(Button)findViewById(R.id.request);

viewCache = LayoutInflater.from(this).inflate(R.layout.pop_layout, null);
mPopupOverlay= new PopupOverlay(mMapView, new PopupClickListener() {// * 点击弹出窗体图层回调的方法
@Override
public void onClickedPopup(int arg0) {
//隐藏弹出窗体图层
mPopupOverlay.hidePop();

}
});

mMapController.enableClick(true);                //*  设置地图是否响应点击事件  .
mMapController.setZoom(12);					// * 设置地图缩放级别
mMapView.setBuiltInZoomControls(true);      // * 显示内置缩放控件
mMapView.setTraffic(true);

mLocData = new LocationData();

mLocClient = new LocationClient(getApplicationContext());  //   * 定位SDK的核心类
//实例化定位服务,LocationClient类必须在主线程中声明
mLocClient.registerLocationListener(new BDLocationListenerImpl());//注冊定位监听接口
/**
* 设置定位參数
*/
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true); //打开GPRS
option.setAddrType("all");//返回的定位结果包括地址信息
option.setCoorType("bd09ll");//返回的定位结果是百度经纬度,默认值gcj02
option.setScanSpan(5000); //设置发起定位请求的间隔时间为5000ms
option.disableCache(false);//禁止启用缓存定位
option.setPoiNumber(5);    //最多返回POI个数
option.setPoiDistance(1000); //poi查询距离
option.setPoiExtraInfo(true);  //是否须要POI的电话和地址等具体信息

mLocClient.setLocOption(option);
mLocClient.start();  //	调用此方法開始定位

myLocationOverlay = new LocationOverlay(mMapView);//定位图层初始化

//将定位数据设置到定位图层里

myLocationOverlay.setMarker(getResources().getDrawable(R.drawable.set));
//加入定位图层
mMapView.getOverlays().add(myLocationOverlay);
myLocationOverlay.enableCompass();

//更新图层数据运行刷新后生效
mMapView.refresh();

/*
//准备要加入的Overlay
double mLat1 = 39.910159;
double mLon1 = 119.544697;

// 用给定的经纬度构造GeoPoint。单位是微度 (度 * 1E6)
GeoPoint p1 = new GeoPoint((int) (mLat1 * 1E6), (int) (mLon1 * 1E6));

//准备overlay图像数据,依据实情情况修复
Drawable mark= getResources().getDrawable(R.drawable.set);
//用OverlayItem准备Overlay数据
OverlayItem item1 = new OverlayItem(p1,"item1","item1");
//使用setMarker()方法设置overlay图片,假设不设置则使用构建ItemizedOverlay时的默认设置

//创建IteminizedOverlay
CustomItemizedOverlay itemOverlay = new CustomItemizedOverlay(mark, mMapView);
//将IteminizedOverlay加入到MapView中

mMapView.getOverlays().clear();
mMapView.getOverlays().add(itemOverlay);

//如今全部准备工作已准备好。使用下面方法管理overlay.
//加入overlay, 当批量加入Overlay时使用addItem(List<OverlayItem>)效率更高
itemOverlay.addItem(item1);
//删除overlay .
//itemOverlay.removeItem(itemOverlay.getItem(0));
//mMapView.refresh();
//清除overlay
// itemOverlay.removeAll();
// mMapView.refresh();
mMapView.refresh();
*/

// mMapController.setCenter(p1);

mMapView.regMapViewListener(mBMapManager, new MKMapViewListener() {
// * 地图移动完毕时会回调此接口 方法
@Override
public void onMapMoveFinish() {
showToast("地图移动完毕。");
}
//* 地图加载完毕回调此接口方法
@Override
public void onMapLoadFinish() {
showToast("地图加载完毕!

");
}
//*  地图完毕带动画的操作(如: animationTo())后。此回调被触发
@Override
public void onMapAnimationFinish() {

}
//当调用过 mMapView.getCurrentMap()后,此回调会被触发  可在此保存截图至存储设备
@Override
public void onGetCurrentMap(Bitmap arg0) {
}
//* 点击地图上被标记的点回调此方法
@Override
public void onClickMapPoi(MapPoi arg0) {
if (arg0 != null){
showToast(arg0.strText);
}
}
});

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
CreateMenu(menu);
return true;
}

private void CreateMenu(Menu menu){
MenuItem mnu1 =menu.add(0,0,0,"显示卫星地图");
{
mnu1.setAlphabeticShortcut('a');//设置快捷键
//mnu1.serIcon(R.drawable.icon);//设置图片
}
MenuItem mnu2 =menu.add(0,1,1,"显示街道地图");
{
mnu2.setAlphabeticShortcut('b');//设置快捷键
//mnu1.serIcon(R.drawable.icon);//设置图片
}
MenuItem mnu3 =menu.add(0,2,2,"3D地图");
{
mnu3.setAlphabeticShortcut('c');//设置快捷键
//mnu1.serIcon(R.drawable.icon);//设置图片
}
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == 0){
mMapView.setSatellite(true);				//设置显示为卫星地图:
mMapView.setTraffic(false);
}else if(item.getItemId() == 1){
mMapView.setTraffic(true);					//显示街道地图
mMapView.setSatellite(false);
}else if(item.getItemId() == 2){
//mMapView.se
}
return true;
}

public class BDLocationListenerImpl implements BDLocationListener {
//  * 接收异步返回的定位结果,參数是BDLocation类型參数
@Override
public void onReceiveLocation(BDLocation location) {
if (location == null) {
return;
}
/*
StringBuffer sb = new StringBuffer(256);
sb.append("time : ");
sb.append(location.getTime());
sb.append("\nerror code : ");
sb.append(location.getLocType());
sb.append("\nlatitude : ");
sb.append(location.getLatitude());
sb.append("\nlontitude : ");
sb.append(location.getLongitude());
sb.append("\nradius : ");
sb.append(location.getRadius());
if (location.getLocType() == BDLocation.TypeGpsLocation){
sb.append("\nspeed : ");
sb.append(location.getSpeed());
sb.append("\nsatellite : ");
sb.append(location.getSatelliteNumber());
} else if (location.getLocType() == BDLocation.TypeNetWorkLocation){
sb.append("\naddr : ");
sb.append(location.getAddrStr());
}
*/
MainActivity.this.location = location;

mLocData.latitude = location.getLatitude();
mLocData.longitude = location.getLongitude();
//假设不显示定位精度圈,将accuracy赋值为0就可以
mLocData.accuracy = location.getRadius();
mLocData.direction = location.getDerect();

//将定位数据设置到定位图层里
myLocationOverlay.setData(mLocData);
//更新图层数据运行刷新后生效
mMapView.refresh();

if(isFirstLoc || isRequest){
//将给定的位置点以动画形式移动至地图中心
mMapController.animateTo(new GeoPoint(
(int) (location.getLatitude() * 1e6), (int) (location.getLongitude() * 1e6)));
showPopupOverlay(location);  //加载时候就弹出
isRequest = false;
}
isFirstLoc = false;

}

// 接收异步返回的POI查询结果。參数是BDLocation类型參数
@Override
public void onReceivePoi(BDLocation poiLocation) {

}

}

private void requestLocation() {
isRequest = true;
if(mLocClient != null && mLocClient.isStarted()){
showToast("正在定位......");
mLocClient.requestLocation();
}
}

//继承MyLocationOverlay重写dispatchTap方法
private class LocationOverlay extends MyLocationOverlay{

public LocationOverlay(MapView arg0) {
super(arg0);
}
//  * 在“我的位置”坐标上处理点击事件。
@Override
protected boolean dispatchTap() {
//点击我的位置显示PopupOverlay
showPopupOverlay(location);
return super.dispatchTap();
}
@Override
public void setMarker(Drawable arg0) {
super.setMarker(arg0);
}

}

@Override
protected void onDestroy() {
//MapView的生命周期与Activity同步,当activity销毁时需调用MapView.destroy()
mMapView.destroy();

//退出应用调用BMapManager的destroy()方法
if(mBMapManager != null){
mBMapManager.destroy();
mBMapManager = null;
}

//退出时销毁定位
if (mLocClient != null){
mLocClient.stop();
}

super.onDestroy();
}

//* 显示弹出窗体图层PopupOverlay
private void showPopupOverlay(BDLocation location){
TextView popText = ((TextView)viewCache.findViewById(R.id.location_tips));
popText.setText("[我的位置]\n" + location.getAddrStr());
mPopupOverlay.showPopup(getBitmapFromView(popText),
new GeoPoint((int)(location.getLatitude()*1e6), (int)(location.getLongitude()*1e6)),
15);

}

// * 将View转换成Bitmap的方法
public static Bitmap getBitmapFromView(View view) {
view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
return bitmap;
}

}


大家注意:这里我把上一次的加入marker的代码凝视了。原因是当我这两个同一时候弄的时候会无法给当前位置加入标记。。。

这个问题稍后会得到解决。

以下的布局文件是弹出框的布局。一个 非常easy的文件:pop_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/location_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/location_tips"
android:maxWidth="200.0dip"
android:minWidth="40.0dip"
android:textColor="@android:color/white" />
/>

</RelativeLayout>


LocationClient 定位SDK的核心类,LocationClient类必须在主线程中声明。

须要Context类型的參数。

Context须要时全进程有效的context,推荐用getApplicationConext获取全进程有效的context,我们调用registerLocationListener(BDLocationListener)方法来注冊定位监听接口,BDLocationListener里面有两个方法,onReceiveLocation()(接收异步返回的定位结果),onReceivePoi()(接收异步返回的POI查询结果。POI是“Point
of Interest”的缩写,能够翻译成“信息点”。每一个POI包括四方面信息。名称、类别、经度、纬度、附近的酒店、饭店,商铺等信息。我们能够叫它为“导航地图信息”,导航地图数据是整个导航产业的基石),我们这里仅仅须要重写onReceiveLocation即可了
BDLocation 封装了定位SDK的定位结果,在BDLocationListener的onReceive方法中获取。通过该类用户能够获取error code,位置的坐标。精度半径,地址等信息,对于其getLocType
()方法获取的error code一些情况

61 : GPS定位结果
62 : 扫描整合定位根据失败。此时定位结果无效。
63 : 网络异常,没有成功向server发起请求。此时定位结果无效。
65 : 定位缓存的结果。

66 : 离线定位结果。通过requestOfflineLocaiton调用时相应的返回结果
67 : 离线定位失败。通过requestOfflineLocaiton调用时相应的返回结果
68 : 网络连接失败时,查找本地离线定位时相应的返回结果
161: 表示网络定位结果
162~167: 服务端定位失败

LocationClientOption 用来设置定位SDK的定位方式。比方设置打开GPS,设置是否须要地址信息,设置发起定位请求的间隔时间等等,參数设置完后调用LocationClient
的setLocOption方法
LocationOverlay MyLocationOverlay的子类,重写里面的dispatchTap()方法,显示弹出窗体图层PopupOverlay,调用mMapView.getOverlays().add(myLocationOverlay)就将我的位置图层加入到地图里面
PopupOverlay 弹出图层,这个类还是比較简单,里面仅仅有三个方法,hidePop() (隐藏弹出图层)showPopup(Bitmap pop, GeoPoint point, int yOffset) (显示弹出图层)和showPopup显示多张图片的重载方法。因为showPopup方法仅仅接受Bitmap对象。所以我们必须将我们的弹出图层View对象转换成Bitmap对象,我们调用getBitmapFromView方法就实现这一转换
BDLocationListener接口的onReceiveLocation(BDLocation location) 方法我还要重点解说下。我们会发现onReceiveLocation方法会重复运行。他运行的间隔跟LocationClientOption类的setScanSpan()方法设定的值有关,我们设定的是5000毫秒,则onReceiveLocation方法每隔5秒运行一次,注意,当我们设定的值大于1000(ms),定位SDK内部使用定时定位模式。

调用requestLocation(
)后,每隔设定的时间,定位SDK就会进行一次定位。

假设定位SDK根据定位根据发现位置没有发生变化,就不会发起网络请求,返回上一次定位的结果。假设发现位置改变,就进行网络请求进行定位。得到新的定位结果。假设你仅仅须要定位一次的话。这个设置小于1000,或者不用设置就能够了,定时定位时,调用一次requestLocation。会定时监听到定位结果

四 . 在执行程序之前,我们还必须在AndroidManifest.xml进行相关配置和权限的声明

<span style="color:#ff6666;"> </span><span style="color:#333333;">   <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.READ_LOGS" /></span>


还有非常重要的一点就是在AndroidManifest.xml中加入以下的内容

<service

android:name="com.baidu.location.f"

android:enabled="true"

android:process=":remote" >

</service>

<meta-data

android:name="com.baidu.lbsapi.API_KEY"

android:value="6KOX4mXHeBRzgriV6OP1T2Hw"

/>

<!-- 致命的一句 -->

当中的meta-data问题:网上这样说,大家记住就得了。







由于单独的定位sdk须要一个key值,而定位sdk的值又不像mapManager中能够直接赋值

所以就须要在注冊表单中注冊

执行图示:


apk地址:http://pan.baidu.com/s/1hqqWSuw

部分内容摘自百度官方文档。部分来自博客:http://blog.csdn.net/xiaanming/article/details/11380619

定位自己的位置基本就这些内容,出现的问题随后会补充上。。

今天就这样吧。。吃饭去了。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: