刚开始做定位功能的时候看了网上的一些教程和博客,但是并没有一份教程真正让我读完就能弄明白并且毫无问题的实现这个功能,所以决定自己写一篇从零开始实现百度定位的教程。
一:一个安卓项目,二:百度SDK,三:百度密钥(也称API key),接下来我会一个个介绍如何准备这些东西。
看到这个在XML文件内的package没有,引号里面的内容就是项目的包名,我这里是com.example.lbs,记起来待会要用。
测试版SHA1值得获取可以看如何获取测试版SHA1值
进入下面的链接百度SDK下载,选择基础定位和基础地图两个功能,如图所示,然后下载开发包。
第一步,注册成为百度开发者。直接点击链接百度控制台,然后登录百度账号,进入下面界面,注册成为百度开发者(相当于是让百度核实一下你确实是个人,而不是机器人)
注册之后.再点击上述链接,可以进入控制台,再进入应用管理,如下图示(可以看到我已经创建了两个应用)
接下来咱们要创建一个应用(只有创建了这个应用,才能获得密钥),如下图所示,应用名称随便写,应用类型填写为Android SDK,启用的服务可以全部勾选,发布版和测试版的SHA1值都填写成之前获取的测试版SHA1值即可。(发布版SHA1值只有当你发布这个项目时才会用到),包名填写之前获取的包名。
点击提交,可以看到我已经创建成功了,而 第二列 的访问应用(AK) 即是我们获取的API Key
我们下载好了百度SDK,但还是没有导入到AS项目中,怎么导入呢。打开之前下载好的SDK,先进行解压,得到下图所示的这些文件(五个so文件夹和一个jar包)
以Project形式展开AS项目,并在src/main下新建一个名为“jniLibs”的文件夹,怕打错字的建议直接复制,如下图所示。
接下来,把SDK文件夹里的jar包丢进上图所示的libs文件夹内,把剩下五个so文件夹丢进jniLbs文件夹内(什么,你问我怎么丢?复制粘贴会不会?)丢进去之后就像下图这样。
还没忙完,只是把包放到了项目内,我们还要同步导入的包,怎么同步?,看AS的右上角,如下图,点击倒数第四个,或者你直接把鼠标移上去,会显示一个Sync巴拉巴拉的信息,那个就是同步按钮了。
怎么判断同步成功了呢?之前导入进去的jar包多了一个小三角,,这就是同步成功的标志。
看到这里你已经完成了大半,你可能会好奇,代码一句都没写怎么就完成了大半呢?因为代码部分我会在下面贴出来,又到了你们最喜欢的拷贝代码环节。
申请权限,先添加下列权限
<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" />
然后在application中分别加入下列代码,以证明你自己是百度开发者,以便百度能让你使用定位服务。
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="你刚刚获取的API Key" />
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" />
加入一个TextureMapView控件,要用来显示地图,为什么用这个而不用MapView?因为MapView在fragment中使用时会导致黑屏一瞬间的bug(这是MapView本身的问题)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/position_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="lbs" />
<com.baidu.mapapi.map.TextureMapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
当然,粘贴的时候别把你原来最上一行的包名也给覆盖了(别问我为什么要提醒你)
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.map.TextureMapView;
import com.baidu.mapapi.model.LatLng;
public class MainActivity extends AppCompatActivity {
private TextureMapView mapView = null;
private BaiduMap baiduMap;
private TextView postionText;
private boolean isFirstLocate = true;
private LocationClient mLocationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationClient = new LocationClient(getApplicationContext());//创建Location实例并接受Context参数
mLocationClient.registerLocationListener(new MyLocationListener());//注册定位监视器,接受位置信息时会回调到该监视器
SDKInitializer.initialize(this.getApplicationContext());//初始化操作,传入Context
setContentView(R.layout.activity_main);
postionText = (TextView) findViewById(R.id.position_text_view);
mapView = (TextureMapView) findViewById(R.id.map);
baiduMap = mapView.getMap();
baiduMap.setMyLocationEnabled(true);//显示当地位置
mLocationClient.start();//开始定位,定位成功后会回调到监视器
initLocation();
}
private void initLocation() {
LocationClientOption option = new LocationClientOption();
option.setCoorType("bd09ll");//直接返回Bi0911坐标系,避免地图纠偏
option.setScanSpan(5000);//每隔5000毫秒更新一次定位信息
option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);//强制GPS
option.setIsNeedAddress(true);//需要精确的信息
mLocationClient.setLocOption(option);
}
class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
if (bdLocation.getLocType() == bdLocation.TypeGpsLocation || bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {
navigateTo(bdLocation);
}
StringBuilder currentPostion = new StringBuilder();
currentPostion.append("纬度:").append(bdLocation.getLatitude()).append("\n");//将经纬度信息转化为国家/省份/城市等信息
currentPostion.append("经度:").append(bdLocation.getLongitude()).append("\n");
currentPostion.append("国家:").append(bdLocation.getCountry()).append("\n");
currentPostion.append("省:").append(bdLocation.getProvince()).append("\n");
currentPostion.append("市:").append(bdLocation.getCity()).append("\n");
currentPostion.append("区:").append(bdLocation.getDistrict()).append("\n");
currentPostion.append("街道:").append(bdLocation.getStreet()).append("\n");
if (bdLocation.getLocType() == bdLocation.TypeGpsLocation) {
//判断定位的类型
currentPostion.append("GPS");
} else if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {
currentPostion.append("网络");
} else {
currentPostion.append("无");
}
postionText.setText(currentPostion);
}
}
private void navigateTo(BDLocation location) {
//显示自己在地图上的位置
if (isFirstLocate) {
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());//存储经纬度到LatLng
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);//显示我所在的区域
update = MapStatusUpdateFactory.zoomTo(16f);//地图显示的缩放级别
baiduMap.animateMapStatus(update);//传入到经纬度
isFirstLocate = false;//防止多次调用
}
MyLocationData.Builder locationBuilder = new MyLocationData.Builder();//将经纬度信息存储到 Builder中
locationBuilder.latitude(location.getLatitude());
locationBuilder.longitude(location.getLongitude());
MyLocationData locationData = locationBuilder.build();
baiduMap.setMyLocationData(locationData);//将我的位置显示出来
}
@Override
public void onResume() {
//重写onResume
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
//重写onPause
super.onPause();
mapView.onPause();
}
@Override
protected void onDestroy() {
//重写onDestroy
super.onDestroy();
mapView.onDestroy();
mLocationClient.stop();
baiduMap.setMyLocationEnabled(false);
}
}
很多时候地图显示并不是写在一个Activity里,而是写在fragment中,这个时候会出现一些意想不到的问题。我在这里分享一下我的Fragment代码可以参考
fragment_lbs.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".LBSFragment">
<TextView
android:id="@+id/position_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="lbs" />
<com.baidu.mapapi.map.TextureMapView
android:id="@+id/map"
android:layout_margin="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
LBSFragment,记得别把你原来最顶上的包名覆盖了
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.map.TextureMapView;
import com.baidu.mapapi.model.LatLng;
public class LBSFragment extends Fragment {
private TextureMapView mapView = null;
private BaiduMap baiduMap;
private boolean isFirstLocate = true;
private LocationClient mLocationClient;
private TextView postionText;
public MyLocationListener myListener = new MyLocationListener();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
SDKInitializer.initialize(getActivity().getApplicationContext());
mLocationClient = new LocationClient(getContext());
mLocationClient.registerLocationListener(myListener);
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_lbs, container, false);
postionText = (TextView) rootView.findViewById(R.id.position_text_view);
mapView = (TextureMapView) rootView.findViewById(R.id.map);
baiduMap = mapView.getMap();
baiduMap.setMyLocationEnabled(true);//显示当地位置
mLocationClient.start();
initLocation();
return rootView;
}
private void navigateTo(BDLocation location) {
if (isFirstLocate) {
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
update = MapStatusUpdateFactory.zoomTo(16f);//缩放级别
baiduMap.animateMapStatus(update);//传入到经纬度
isFirstLocate = false;//防止多次调用
}
MyLocationData.Builder locationBuilder = new MyLocationData.Builder();
locationBuilder.latitude(location.getLatitude());
locationBuilder.longitude(location.getLongitude());
MyLocationData locationData = locationBuilder.build();
baiduMap.setMyLocationData(locationData);
}
private void initLocation() {
//设置更新时间的间隔
LocationClientOption option = new LocationClientOption();
option.setCoorType("bd09ll");
option.setScanSpan(5000);//每隔5000毫秒一次更新
option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);//强制GPS
option.setIsNeedAddress(true);//需要精确的信息
mLocationClient.setLocOption(option);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mapView.onDestroy();
mLocationClient.stop();
baiduMap.setMyLocationEnabled(false);
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
//
class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
if (bdLocation.getLocType() == bdLocation.TypeGpsLocation || bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {
navigateTo(bdLocation);
}
StringBuilder currentPostion = new StringBuilder();
currentPostion.append("纬度:").append(bdLocation.getLatitude()).append("\n");
currentPostion.append("经度:").append(bdLocation.getLongitude()).append("\n");
currentPostion.append("国家:").append(bdLocation.getCountry()).append("\n");
currentPostion.append("省:").append(bdLocation.getProvince()).append("\n");
currentPostion.append("市:").append(bdLocation.getCity()).append("\n");
currentPostion.append("区:").append(bdLocation.getDistrict()).append("\n");
currentPostion.append("街道:").append(bdLocation.getStreet()).append("\n");
if (bdLocation.getLocType() == bdLocation.TypeGpsLocation) {
currentPostion.append("GPS");
} else if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {
currentPostion.append("网络");
} else {
currentPostion.append("无");
}
postionText.setText(currentPostion);
}
}
}