浅析Android地理定位(GPS)
淺析Android地理定位(GPS)
- 定位權(quán)限
- 介紹一下定位相關(guān)的一些API
- LocationManager
- 位置提供器
- requestLocationUpdates
- Geocoder
- Criteria 和 Address
- 實(shí)現(xiàn)代碼
- 實(shí)現(xiàn)效果
- 補(bǔ)充
關(guān)于手機(jī)的定位服務(wù),相信大家都不陌生,如今國(guó)內(nèi)安卓手機(jī)上大面積使用了北斗+GPS的定位方式。通過(guò)與衛(wèi)星交互來(lái)獲取設(shè)備當(dāng)前的經(jīng)緯度,準(zhǔn)確度較高。
GPS是英文Global Positioning System(全球定位系統(tǒng))的簡(jiǎn)稱。Android中定位的方式一般有這四種:GPS定位,WIFI定準(zhǔn),基站定位,AGPS定位(基站+GPS);
本篇主要介紹谷歌自帶的LocationManager 獲取手機(jī)定位的方法,以及通過(guò)谷歌服務(wù)Geocoder 來(lái)進(jìn)行反地理編碼。但是由于Geocoder 進(jìn)行反地理編碼需要一個(gè)未包含在android核心框架之中的后端服務(wù),如果平臺(tái)中沒(méi)有這個(gè)后端服務(wù),Geocoder查詢方法將返回空列表。不幸的是,國(guó)內(nèi)很多手機(jī)廠商都沒(méi)有內(nèi)置這種服務(wù)(例如百度、高德服務(wù)),所以Geocoder也就不能使用了。所以為了穩(wěn)定,只能選擇國(guó)內(nèi)的反地理編碼web服務(wù)了。
定位權(quán)限
1.Manifest文件添加權(quán)限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>2.添加依賴
mplementation "com.google.code.gson:gson:2.8.5"implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"implementation "org.jetbrains.kotlinx:kotlinximplementation 'com.afollestad:assent:2.3.1' ##介紹一下定位相關(guān)的一些API
1)LocationManager
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);獲得了LocationManager對(duì)象后,我們可以調(diào)用下面這些常用的方法:
addGpsStatusListener(GpsStatus.Listener listener):添加一個(gè)GPS狀態(tài)監(jiān)聽(tīng)器
addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent):
添加一個(gè)臨界警告
getAllProviders():獲取所有的LocationProvider列表
getBestProvider(Criteria criteria, boolean enabledOnly):根據(jù)指定條件返回最優(yōu)LocationProvider
getGpsStatus(GpsStatus status):獲取GPS狀態(tài)
getLastKnownLocation(String provider):根據(jù)LocationProvider獲得最近一次已知的Location
getProvider(String name):根據(jù)名稱來(lái)獲得LocationProvider
getProviders(boolean enabledOnly):獲取所有可用的LocationProvider
getProviders(Criteria criteria, boolean enabledOnly):根據(jù)指定條件獲取滿足條件的所有LocationProvider
isProviderEnabled(String provider):判斷指定名稱的LocationProvider是否可用
removeGpsStatusListener(GpsStatus.Listener listener):刪除GPS狀態(tài)監(jiān)聽(tīng)器
removeProximityAlert(PendingIntent intent):刪除一個(gè)臨近警告
requestLocationUpdates(long minTime, float minDistance, Criteria criteria, PendingIntent intent):
通過(guò)制定的LocationProvider周期性地獲取定位信息,并通過(guò)Intent啟動(dòng)相應(yīng)的組件
requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener):
通過(guò)制定的LocationProvider周期性地獲取定位信息,并觸發(fā)listener所對(duì)應(yīng)的觸發(fā)器
2)LocationProvider(定位提供者)
這比是GPS定位組件的抽象表示,調(diào)用下述方法可以獲取該定位組件的相關(guān)信息!
常用的方法如下:
getAccuracy():返回LocationProvider精度
getName():返回LocationProvider名稱
getPowerRequirement():獲取LocationProvider的電源需求
hasMonetaryCost():返回該LocationProvider是收費(fèi)還是免費(fèi)的
**meetsCriteria(**Criteria criteria):判斷LocationProvider是否滿足Criteria條件
requiresCell():判斷LocationProvider是否需要訪問(wèn)網(wǎng)絡(luò)基站
requiresNetwork():判斷LocationProvider是否需要訪問(wèn)網(wǎng)絡(luò)數(shù)據(jù)
requiresSatellite():判斷LocationProvider是否需要訪問(wèn)基于衛(wèi)星的定位系統(tǒng)
supportsAltitude():判斷LocationProvider是否支持高度信息
supportsBearing():判斷LocationProvider是否支持方向信息
supportsSpeed():判斷是LocationProvider否支持速度信息
3)Location(位置信息)
位置信息的抽象類,我們可以調(diào)用下述方法獲取相關(guān)的定位信息!
常用方法如下:
float getAccuracy():獲得定位信息的精度
double getAltitude():獲得定位信息的高度
float getBearing():獲得定位信息的方向
double getLatitude():獲得定位信息的緯度
double getLongitude():獲得定位信息的精度
String getProvider():獲得提供該定位信息的LocationProvider
float getSpeed():獲得定位信息的速度
boolean hasAccuracy():判斷該定位信息是否含有精度信息
4)Criteria(過(guò)濾條件)
獲取LocationProvider時(shí),可以設(shè)置過(guò)濾條件,就是通過(guò)這個(gè)類來(lái)設(shè)置相關(guān)條件的
常用方法如下:
setAccuracy(int accuracy):設(shè)置對(duì)的精度要求
setAltitudeRequired(boolean altitudeRequired):設(shè)置是否要求LocationProvider能提供高度的信息
setBearingRequired(boolean bearingRequired):設(shè)置是否要LocationProvider求能提供方向信息
setCostAllowed(boolean costAllowed):設(shè)置是否要求LocationProvider能提供方向信息
setPowerRequirement(int level):設(shè)置要求LocationProvider的耗電量
setSpeedRequired(boolean speedRequired):設(shè)置是否要求LocationProvider能提供速度信息
LocationManager
LocationManager 的api使用起來(lái)很簡(jiǎn)單,難點(diǎn)在于不同android機(jī)型,不同系統(tǒng)可能存在著很多未知的坑。最大的坑就是有的手機(jī)系統(tǒng)底層的定位服務(wù)是直接連接的google服務(wù)器,手機(jī)廠商沒(méi)有將定位的服務(wù)器重定向?yàn)閲?guó)內(nèi)的定位服務(wù)商,致使我們通過(guò)LocationManager根本拿不到定位信息。
位置提供器
LocationManager 提供的位置提供器,默認(rèn)為PASSIVE_PROVIDER,這是一個(gè)特殊的位置提供器,用來(lái)被動(dòng)的接收位置信息,這個(gè)位置信息是由其他的服務(wù)提供的位置信息,而不是自己主動(dòng)請(qǐng)求的,相當(dāng)于共享了一個(gè)位置服務(wù)信息,不常用。使用比較多的還是GPS和網(wǎng)絡(luò)定位,這兩種定位方式各有特點(diǎn),GPS定位精度高,但是比較耗電,而且室內(nèi)很難獲取到GPS經(jīng)緯度。而網(wǎng)絡(luò)定位雖然精度稍低,但耗電量比較小,而且在室內(nèi)室外效果都很不錯(cuò)。
lm = (LocationManager) mContext.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);// 檢查是否有相關(guān)定位權(quán)限if(!Helper.checkPermission(mContext.getApplicationContext())){mListener.onFail("location no permission");return;}// 如果不傳配置類,則按默認(rèn)配置if(mSiLoOption == null)mSiLoOption = new SiLoOption();mProvider = mSiLoOption.isGpsFirst ? Helper.getGPSProvider(lm) : Helper.getNetWorkProvider(lm);if(mProvider == null)mListener.onFail("location provider no exist");elsegetLocation(mProvider);獲取gps位置提供器的代碼片段:
/*** gps 提供器* @param locationManager* @return*/public static String getGPSProvider(LocationManager locationManager) {List<String> prodiverlist = locationManager.getProviders(true);// gps定位if(prodiverlist.contains(LocationManager.GPS_PROVIDER))return LocationManager.GPS_PROVIDER;return null;}requestLocationUpdates
獲取位置提供器成功后,就可以通過(guò)requestLocationUpdates 方法來(lái)請(qǐng)求經(jīng)緯度了
下面是邏輯代碼片段:
Geocoder
Geocoder 的api很簡(jiǎn)單,如果國(guó)內(nèi)手機(jī)在自定義系統(tǒng)時(shí)能夠使用geooder的后端服務(wù)或已內(nèi)置百度高德服務(wù),那么使用Geocoder 反地理編碼功能會(huì)很方便。所以在使用前,我們可以先檢查服務(wù)是否可用,再?zèng)Q定使用哪家的web 反地理編碼服務(wù)。
if(!Geocoder.isPresent()){if(mListener != null)mListener.onFail(ResponseConstant.GOOGLE_API_OUT_OF_CONDITON, "geocoder is out of condition");return; }Criteria 和 Address
根據(jù)Criteria 指定的條件,設(shè)備可以自動(dòng)選擇那種provider、是否要求海波、是否要求方向;設(shè)置電池消耗要求、設(shè)置方向的精準(zhǔn)度等一系列的篩選條件。但這里需要注意的是,network一般根據(jù)wifi節(jié)點(diǎn)mac地址和基站地理位置來(lái)進(jìn)行定位的,在精度上來(lái)說(shuō)是比較差的,雖然有的手機(jī)返回的經(jīng)緯度的精度級(jí)別非常高,但是其實(shí)際偏差卻是非常大的,所以我們不能完全信賴net定位點(diǎn)。
Address 是反編碼成功后的實(shí)體bean,并沒(méi)有什么特殊的地方,只是存儲(chǔ)了谷歌服務(wù)返回來(lái)的字段值罷了。例如我們平時(shí)常用的國(guó)家、城市、城市編碼、區(qū)、街道、POi名稱等信息。
實(shí)現(xiàn)代碼
獲取經(jīng)緯度代碼:LocationManager獲取經(jīng)緯度
import android.content.Context; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationProvider; import android.os.Build; import android.os.Bundle;import androidx.annotation.Nullable;import com.mjzuo.location.bean.Latlng; import com.mjzuo.location.helper.ConverHelper; import com.mjzuo.location.helper.Helper; import com.mjzuo.location.util.LogUtil;ic class GoogleGeocoding implements IGeocoding {/** 當(dāng)前系統(tǒng)定位manager*/private LocationManager lm;/** 位置提供器*/private String mProvider;/** 定位change監(jiān)聽(tīng)*/private MyLocationListener mChangeListener;/** 響應(yīng)用戶的回調(diào)*/private ISiLoResponseListener mListener;/** 服務(wù)的參數(shù)配置類*/private SiLoOption mSiLoOption;/** 當(dāng)前經(jīng)緯度*/private Latlng latlng;/** 計(jì)數(shù)器*/private int mCounter;/** gps信號(hào)消失,嘗試network定位*/private static final int GPS_TIME_SPACE = 6;/** 嘗試network之后,同樣獲取不到定位,則錯(cuò)誤回調(diào),時(shí)間間隔 = NET_TIME_SPACE - GPS_TIME_SPACE*/private static final int NET_TIME_SPACE = 12;private Context mContext;public GoogleGeocoding(Context context) {this.mContext = context;this.mChangeListener = new MyLocationListener();}public void setSimpleLocationOption(@Nullable SiLoOption siLoOption) {this.mSiLoOption = siLoOption;}@Overridepublic void start(@Nullable ISiLoResponseListener listener) {if(listener != null)this.mListener = listener;if(mListener == null)return;lm = (LocationManager) mContext.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);// 檢查是否有相關(guān)定位權(quán)限if(!Helper.checkPermission(mContext.getApplicationContext())){mListener.onFail("location no permission");return;}// 如果不傳配置類,則按默認(rèn)配置if(mSiLoOption == null)mSiLoOption = new SiLoOption();mProvider = mSiLoOption.isGpsFirst ? Helper.getGPSProvider(lm) : Helper.getNetWorkProvider(lm);if(mProvider == null)mListener.onFail("location provider no exist");elsegetLocation(mProvider);}@Overridepublic void reStart() {start(null);}@Overridepublic void stop() {mProvider = null;if(lm != null)lm.removeUpdates(mChangeListener);lm = null;mListener = null;mChangeListener = null;}@SuppressWarnings("all")private String getLocation(String provider) {if(provider == null)return null;lm.requestLocationUpdates(provider, mSiLoOption.time, mSiLoOption.distance, mChangeListener);return provider;}class MyLocationListener implements LocationListener {@Overridepublic void onLocationChanged(Location location) {if(mProvider == null)return;latlng = location != null ? ConverHelper.loConverToLatlng(location) : latlng;mListener.onSuccess(latlng);if(mSiLoOption.isGpsFirst){if(location != null){if(mProvider == LocationManager.GPS_PROVIDER)mCounter = 0;else{mCounter += mSiLoOption.time/1000;if(mCounter > NET_TIME_SPACE){mProvider = getLocation(Helper.getGPSProvider(lm));mCounter = 0;}}}else{// gps無(wú)信號(hào)時(shí),嘗試network獲取mCounter += mSiLoOption.time/1000;if(mCounter >= GPS_TIME_SPACE && mCounter < NET_TIME_SPACE){mProvider = getLocation(Helper.getNetWorkProvider(lm));}else if(mCounter > NET_TIME_SPACE){// 只要最后一個(gè)net點(diǎn)失敗,就拋出回調(diào);前兩個(gè)點(diǎn),由于開(kāi)始,可能為空,不做強(qiáng)制判斷處理mListener.onFail("location latlng = null , provider = "+ mProvider);}}}else{// 當(dāng)network獲取不到定位if(location == null)mListener.onFail("location latlng = null , provider = "+ mProvider);}}@Overridepublic void onStatusChanged(String s, int state, Bundle bundle) {if(mListener == null)return;if(Build.VERSION.SDK_INT > 28){LogUtil.e("after api 29 always AVAILABLE");}else{switch (state){case LocationProvider.OUT_OF_SERVICE:case LocationProvider.TEMPORARILY_UNAVAILABLE:LogUtil.e("current provider out of condition");break;}}}@Overridepublic void onProviderEnabled(String s) {}@Overridepublic void onProviderDisabled(String s) {}}public static class SiLoOption {/*** gps 優(yōu)先否*/private boolean isGpsFirst = false;/*** 監(jiān)聽(tīng)定位變化最短時(shí)間間隔,默認(rèn)time s*/private int time = 2000;/*** 監(jiān)聽(tīng)變化的最小距離*/private int distance = 10;public boolean isGpsFirst() {return isGpsFirst;}public SiLoOption setGpsFirst(boolean gpsFirst) {isGpsFirst = gpsFirst;return this;}public int getTime() {return time;}public SiLoOption setTime(int time) {this.time = time;return this;}public int getRequestTepe() {return distance;}public SiLoOption setRequestTepe(int requestTepe) {this.distance = requestTepe;return this;}} }獲取經(jīng)緯度代碼:定位類
import android.content.Context;import androidx.annotation.Nullable;import com.mjzuo.location.constant.Constant; import com.mjzuo.location.helper.GeReFactory; import com.mjzuo.location.location.GoogleGeocoding; import com.mjzuo.location.location.IGeocoding; import com.mjzuo.location.util.LogUtil;ic class GeocodingManager {private IGeocoding mGeocoding;private IGeocoding.ISiLoResponseListener mListener;private Context mContext;public GeocodingManager(Context context) {mContext = context;mGeocoding = GeReFactory.getGeocodingType(mContext, Constant.LM_API);}public GeocodingManager(Context context, @Nullable GeoOption option) {mContext = context;mGeocoding = GeReFactory.getGeocodingType(mContext, option.getGeoType());if(mGeocoding instanceof GoogleGeocoding)((GoogleGeocoding) mGeocoding).setSimpleLocationOption(option.getOption());}public void start(IGeocoding.ISiLoResponseListener listener) {if(listener != null)mListener = listener;if(mListener == null){LogUtil.e("simple location response listener null");}mGeocoding.start(mListener);}public void reStart(){start(null);}public void stop(){mGeocoding = null;mListener = null;}public static class GeoOption {/*** 定位的類型** LocationManager或基站定位*/private int GeoType = Constant.LM_API;/*** 這是locationManager的配置類*/private GoogleGeocoding.SiLoOption option;public int getGeoType() {return GeoType;}public GeoOption setGeoType(int geoType) {GeoType = geoType;return this;}public GoogleGeocoding.SiLoOption getOption() {return option;}public GeoOption setOption(GoogleGeocoding.SiLoOption option) {this.option = option;return this;}}}百度API接口:
import android.content.Context; import android.os.AsyncTask;import androidx.annotation.Nullable;import com.mjzuo.location.ReverseGeocodingManager; import com.mjzuo.location.bean.Latlng; import com.mjzuo.location.constant.UrlConstant; import com.mjzuo.location.helper.Helper; import com.mjzuo.location.net.NetUtil; import com.mjzuo.location.util.CommonUtil; import com.mjzuo.location.util.LogUtil;import org.json.JSONObject;import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.LinkedHashMap; import java.util.Map;public class BaiduGeRe implements IReGe {private String ak = "KHVTQZiP2UGuv7SkNbqYPKu4co7kbkS4";private String sk = "cTqIacm4uvDnQWpWWCZGElhbIx4Nxv3q";private String host = "/reverse_geocoding/v3/";private LinkedHashMap<String, String> paramsMap;// 默認(rèn)使用sn校驗(yàn)方式private boolean isSn = true;private MyAsyncTask task;private IReGeListener mListener;@Overridepublic void init(@Nullable Context context) {paramsMap = new LinkedHashMap<>();paramsMap.put("ak", ak);paramsMap.put("coordtype", "wgs84ll");}@Overridepublic void setOptions(@Nullable ReverseGeocodingManager.ReGeOption options) {this.isSn = options.isSn();if(options.getKey() != null && !options.getKey().isEmpty())this.ak = options.getKey();if(options.getSk() != null && !options.getSk().isEmpty())this.sk = options.getSk();}@Overridepublic void reGeToAddress(Latlng latlng) {paramsMap.put("location", latlng.getLatitude() + "," + latlng.getLongitude());paramsMap.put("output", "json");if(isSn) {String paramsStr;try {paramsStr = toQueryString(paramsMap);}catch (UnsupportedEncodingException e){LogUtil.e("error:"+e.getMessage());return;}String wholeStr = new String(host + "?" + paramsStr + sk);try {wholeStr = URLEncoder.encode(wholeStr, "UTF-8");}catch (Exception e){LogUtil.e("error:"+e.getMessage());return;}String sn = CommonUtil.MD5(wholeStr);paramsMap.put("sn", sn);}task = new MyAsyncTask(Helper.toAppendUrl(paramsMap, UrlConstant.BAIDU_URL, host));task.execute();}@Overridepublic void stop() {if(paramsMap != null)paramsMap.clear();paramsMap = null;task = null;}@Overridepublic void addReGeListener(IReGeListener listener) {mListener = listener;}class MyAsyncTask extends AsyncTask<Void, Void, String>{String mUrl;public MyAsyncTask(String url) {mUrl = url;}@Overrideprotected String doInBackground(Void... voids) {return NetUtil.doHttpGet(mUrl);}@Overrideprotected void onPostExecute(String json) {super.onPostExecute(json);fromJson(json);task = null;}}/*** 對(duì)Map內(nèi)所有value作utf8編碼,拼接返回結(jié)果* @param data* @return* @throws UnsupportedEncodingException*/private String toQueryString(Map<?, ?> data)throws UnsupportedEncodingException {StringBuffer queryString = new StringBuffer();for (Map.Entry<?, ?> pair : data.entrySet()) {queryString.append(pair.getKey() + "=");queryString.append(URLEncoder.encode((String) pair.getValue(),"UTF-8") + "&");}if (queryString.length() > 0) {queryString.deleteCharAt(queryString.length() - 1);}return queryString.toString();}/*** 解析json*/private void fromJson(String json) {LogUtil.e("json:"+json);if(json == null || json.isEmpty())return;if(mListener == null)return;JSONObject jsonObject = null;try {jsonObject = new JSONObject(json);}catch (Exception e){LogUtil.e("error:" + e.getMessage());return;}if(jsonObject.has("status")){Integer state;try {state = (Integer) jsonObject.get("status");// 0請(qǐng)求成功標(biāo)志碼if(state != 0){if(jsonObject.has("message"))mListener.onFail(state, jsonObject.getString("message"));return;}if(jsonObject.has("result")){JSONObject obj;JSONObject objAddress;try{obj = jsonObject.getJSONObject("result");objAddress = obj.getJSONObject("addressComponent");Latlng latlng = new Latlng();latlng.setCountry(objAddress.getString("country"));latlng.setCountryCode(objAddress.getString("country_code"));latlng.setCity(objAddress.getString("city"));latlng.setSublocality(objAddress.getString("district"));latlng.setCityCode(obj.getInt("cityCode")+"");latlng.setAddress(objAddress.getString("street"));latlng.setName(obj.getString("business"));mListener.onSuccess(state, latlng);}catch (Exception e){LogUtil.e("error:"+e.getMessage());return;}}}catch (Exception e){LogUtil.e("error:" + e.getMessage());return;}}} }反向地理編碼:
/** 百度api返地理編碼*/ public static final String BAIDU_URL = "https://api.map.baidu.com";/**特定經(jīng)緯度的反向地理編碼:*/ import android.content.Context;import androidx.annotation.Nullable;import com.mjzuo.location.bean.Latlng; import com.mjzuo.location.constant.Constant; import com.mjzuo.location.helper.GeReFactory; import com.mjzuo.location.regelocation.IReGe; import com.mjzuo.location.util.LogUtil;lic class ReverseGeocodingManager {IReGe mGeRe;Context mContext;public ReverseGeocodingManager(Context context) {mContext = context;mGeRe = GeReFactory.getReGeByType(Constant.GOOGLE_API);mGeRe.init(mContext);}public ReverseGeocodingManager(Context context, @Nullable ReGeOption option) {mContext = context;mGeRe = GeReFactory.getReGeByType(option.getReGeType());mGeRe.setOptions(option);mGeRe.init(mContext);}public void reGeToAddress(@Nullable Latlng latlng) {mGeRe.reGeToAddress(latlng);}public void stop() {mGeRe.stop();}public void addReGeListener(@Nullable IReGe.IReGeListener listener) {mGeRe.addReGeListener(listener);}public static class ReGeOption {/*** api類型,默認(rèn)谷歌服務(wù)** 注意:個(gè)別機(jī)型內(nèi)部移除了谷歌服務(wù),如果不能請(qǐng)求,請(qǐng)切換別的api接口*/private int reGeType = Constant.GOOGLE_API;/*** 是否sn校驗(yàn),默認(rèn)簽名校驗(yàn)方式,而非白名單方式*/private boolean isSn = true;/*** key*/private String key = "";/*** sk*/private String sk = "";/*** 是否打開(kāi)log*/private boolean islog = true;public int getReGeType() {return reGeType;}public ReGeOption setReGeType(int reGeType) {this.reGeType = reGeType;return this;}public boolean isSn() {return isSn;}public ReGeOption setSn(boolean sn) {isSn = sn;return this;}public boolean isIslog() {return LogUtil.DEBUG;}public ReGeOption setIslog(boolean islog) {LogUtil.DEBUG = islog;return this;}public String getKey() {return key;}public String getSk() {return sk;}public ReGeOption setKey(String key) {this.key = key;return this;}public ReGeOption setSk(String sk) {this.sk = sk;return this;}} }LocationTaskActivity:
import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity;import android.Manifest; import android.os.Bundle; import android.util.Log; import android.widget.TextView;import com.mjzuo.location.GeocodingManager; import com.mjzuo.location.bean.Latlng; import com.mjzuo.location.constant.Constant; import com.mjzuo.location.location.GoogleGeocoding; import com.mjzuo.location.location.IGeocoding; import com.mjzuo.location.regelocation.IReGe; import com.mjzuo.location.ReverseGeocodingManager;import java.util.List;import pub.devrel.easypermissions.EasyPermissions;public class LocationTaskActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks{private static final String LOG_TAG = "tag_sl";/** 所要申請(qǐng)的權(quán)限*/String[] perms = {Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.INTERNET,Manifest.permission.READ_PHONE_STATE};/** 定位獲取經(jīng)緯度,包括LocationManager、基站地位*/GeocodingManager siLoManager;/** 反地理編碼的manager,包括google反地理、百度反地理*/ReverseGeocodingManager reGeManager;TextView tvSimpleLo;TextView tvSimpleAd;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.simple_location_activity);tvSimpleLo = findViewById(R.id.tv_simple_location_txt);tvSimpleAd = findViewById(R.id.tv_simple_address_txt);if (!EasyPermissions.hasPermissions(this, perms)) {EasyPermissions.requestPermissions(this, "必要的權(quán)限", 0, perms);}ReverseGeocodingManager.ReGeOption reGeOption = new ReverseGeocodingManager.ReGeOption().setReGeType(Constant.BAIDU_API)// 百度api返地理編碼.setSn(true)// sn 簽名校驗(yàn)方式.setIslog(true);// 打印logreGeManager = new ReverseGeocodingManager(this, reGeOption);reGeManager.addReGeListener(new IReGe.IReGeListener() {@Overridepublic void onSuccess(int state, Latlng latlng) {Log.e(LOG_TAG,"reGeManager onSuccess:" + latlng);tvSimpleAd.setText("country:"+ latlng.getCountry()+ "\n,city:" + latlng.getCity()+ "\n,sublocality:" + latlng.getSublocality()+ "\n,address:" + latlng.getAddress()+ "\n,name:" + latlng.getName());}@Overridepublic void onFail(int errorCode, String error) {Log.e(LOG_TAG,"error:" + error);tvSimpleAd.setText("errorCode:"+errorCode+", error:" + error);}});GeocodingManager.GeoOption option = new GeocodingManager.GeoOption().setGeoType(Constant.LM_API) // 使用openCellid服務(wù)器的基站地位.setOption(new GoogleGeocoding.SiLoOption().setGpsFirst(true));// locationManager定位方式時(shí),gps優(yōu)先siLoManager = new GeocodingManager(this, option);siLoManager.start(new IGeocoding.ISiLoResponseListener() {@Overridepublic void onSuccess(Latlng latlng) {Log.e(LOG_TAG,"siLoManager onSuccess:" + latlng);tvSimpleLo.setText("latlng:" + latlng.getLatitude()+ "\n,long:" + latlng.getLongitude()+ "\n,provider:" + latlng.getProvider());reGeManager.reGeToAddress(latlng);}@Overridepublic void onFail(String msg) {Log.e(LOG_TAG,"error:" + msg);tvSimpleAd.setText("error:" + msg);}});}@Overrideprotected void onDestroy() {super.onDestroy();if(siLoManager != null)siLoManager.stop();if(reGeManager != null){reGeManager.stop();}}@Overridepublic void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {if(requestCode == 0 && siLoManager != null)siLoManager.reStart();}@Overridepublic void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {}@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);// Forward results to EasyPermissionsEasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);} }實(shí)現(xiàn)效果
請(qǐng)求用戶權(quán)限
不開(kāi)啟GPS定位下的效果
開(kāi)啟定位服務(wù)
上地圖查一下,結(jié)果十分的正確
補(bǔ)充
百度API使用方法官網(wǎng)鏈接
檢測(cè)到GPS未打開(kāi)時(shí)間,讓用戶自行打開(kāi)
——————————————————————————————
參考鏈接:https://www.runoob.com/w3cnote/android-tutorial-gps.html.
參考鏈接:https://blog.csdn.net/MingJieZuo/article/details/79755357.
總結(jié)
以上是生活随笔為你收集整理的浅析Android地理定位(GPS)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一个门外汉的产品设计漫谈:从初级到神级的
- 下一篇: Android9怎么剪辑音频,音频剪辑铃