Android Studio利用百度地圖SDK實現定位功能
前言
剛開始做定位功能的時候看了網上的一些教程和博客,但是並沒有一份教程真正讓我讀完就能弄明白並且毫無問題的實現這個功能,所以決定自己寫一篇從零開始實現百度定位的教程。
需要提前準備的東西
一:一個安卓項目,二:百度SDK,三:百度密鑰(也稱API key),接下來我會一個個介紹如何準備這些東西。
新建一個AS項目,獲取包名和測試版SHA1值
看到這個在XML文件內的package沒有,引號裏面的內容就是項目的包名,我這裏是com.example.lbs,記起來待會要用。
測試版SHA1值得獲取可以看如何獲取測試版SHA1值
下載百度SDK
進入下面的鏈接百度SDK下載,選擇基礎定位和基礎地圖兩個功能,如圖所示,然後下載開發包。
獲取百度密鑰(API Key)
第一步,註冊成爲百度開發者。直接點擊鏈接百度控制檯,然後登錄百度賬號,進入下面界面,註冊成爲百度開發者(相當於是讓百度覈實一下你確實是個人,而不是機器人)
註冊之後.再點擊上述鏈接,可以進入控制檯,再進入應用管理,如下圖示(可以看到我已經創建了兩個應用)
接下來咱們要創建一個應用(只有創建了這個應用,才能獲得密鑰),如下圖所示,應用名稱隨便寫,應用類型填寫爲Android SDK,啓用的服務可以全部勾選,發佈版和測試版的SHA1值都填寫成之前獲取的測試版SHA1值即可。(發佈版SHA1值只有當你發佈這個項目時纔會用到),包名填寫之前獲取的包名。
點擊提交,可以看到我已經創建成功了,而 第二列 的訪問應用(AK) 即是我們獲取的API Key
導入百度SDK
我們下載好了百度SDK,但還是沒有導入到AS項目中,怎麼導入呢。打開之前下載好的SDK,先進行解壓,得到下圖所示的這些文件(五個so文件夾和一個jar包)
以Project形式展開AS項目,並在src/main下新建一個名爲“jniLbs”的文件夾,怕打錯字的建議直接複製,如下圖所示。
接下來,把SDK文件夾裏的jar包丟進上圖所示的libs文件夾內,把剩下五個so文件夾丟進jniLbs文件夾內(什麼,你問我怎麼丟?複製粘貼會不會?)丟進去之後就像下圖這樣。
還沒忙完,只是把包放到了項目內,我們還要同步導入的包,怎麼同步?,看AS的右上角,如下圖,點擊倒數第四個,或者你直接把鼠標移上去,會顯示一個Sync巴拉巴拉的信息,那個就是同步按鈕了。
怎麼判斷同步成功了呢?之前導入進去的jar包多了一個小三角,,這就是同步成功的標誌。
代碼實現
看到這裏你已經完成了大半,你可能會好奇,代碼一句都沒寫怎麼就完成了大半呢?因爲代碼部分我會在下面貼出來,又到了你們最喜歡的拷貝代碼環節。
配置AndroidManifest.xml
申請權限,先添加下列權限
<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" />
MainActivity.xml
加入一個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"
tools:context=".MainActivity">
<com.baidu.mapapi.map.TextureMapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
MainActivity
當然,粘貼的時候別把你原來最上一行的包名也給覆蓋了(別問我爲什麼要提醒你)
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);
}
}
注意事項:程序想看效果一定要在真機上跑!!!!虛擬機上帶不帶GPS你想過沒得?別問我爲什麼提醒你
關於在Fragment中實現地圖的顯示
很多時候地圖顯示並不是寫在一個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);
}
}
}