LocationManager 提供的位置提供器,默认为PASSIVE_PROVIDER,这是一个特殊的位置提供器,用来被动的接收位置信息,这个位置信息是由其他的服务提供的位置信息,而不是自己主动请求的,相当于共享了一个位置服务信息,不常用。使用比较多的还是GPS和网络定位,这两种定位方式各有特点,GPS定位精度高,但是比较耗电,而且室内很难获取到GPS经纬度。而网络定位虽然精度稍低,但耗电量比较小,而且在室内室外效果都很不错。
lm = (LocationManager) mContext.getApplicationContext()
.getSystemService(Context.LOCATION_SERVICE);
// 检查是否有相关定位权限
if(!Helper.checkPermission(mContext.getApplicationContext())){
mListener.onFail(“location no permission”);
return;
}
// 如果不传配置类,则按默认配置
if(mSiLoOption == null)
mSiLoOption = new SiLoOption();
mProvider = mSiLoOption.isGpsFirst ? Helper.getGPSProvider(lm) : Helper.getNetWorkProvider(lm);
if(mProvider == null)
mListener.onFail(“location provider no exist”);
else
getLocation(mProvider);
获取gps位置提供器的代码片段:
/**
-
gps 提供器
-
@param locationManager
-
@return
*/
public static String getGPSProvider(LocationManager locationManager) {
List prodiverlist = locationManager.getProviders(true);
// gps定位
if(prodiverlist.contains(LocationManager.GPS_PROVIDER))
return LocationManager.GPS_PROVIDER;
return null;
}
获取位置提供器成功后,就可以通过requestLocationUpdates 方法来请求经纬度了
下面是逻辑代码片段:
@Override
public 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无信号时,尝试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){
// 只要最后一个net点失败,就抛出回调;前两个点,由于开始,可能为空,不做强制判断处理
mListener.onFail("location latlng = null , provider = "+ mProvider);
}
}
}else{
// 当network获取不到定位
if(location == null)
mListener.onFail("location latlng = null , provider = "+ mProvider);
}
}
Geocoder 的api很简单,如果国内手机在自定义系统时能够使用geooder的后端服务或已内置百度高德服务,那么使用Geocoder 反地理编码功能会很方便。所以在使用前,我们可以先检查服务是否可用,再决定使用哪家的web 反地理编码服务。
if(!Geocoder.isPresent()){
if(mListener != null)
mListener.onFail(ResponseConstant.GOOGLE_API_OUT_OF_CONDITON, “geocoder is out of condition”);
return;
}
根据Criteria 指定的条件,设备可以自动选择那种provider、是否要求海波、是否要求方向;设置电池消耗要求、设置方向的精准度等一系列的筛选条件。但这里需要注意的是,network一般根据wifi节点mac地址和基站地理位置来进行定位的,在精度上来说是比较差的,虽然有的手机返回的经纬度的精度级别非常高,但是其实际偏差却是非常大的,所以我们不能完全信赖net定位点。
Address 是反编码成功后的实体bean,并没有什么特殊的地方,只是存储了谷歌服务返回来的字段值罢了。例如我们平时常用的国家、城市、城市编码、区、街道、POi名称等信息。
获取经纬度代码:LocationManager获取经纬度
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 {
/** 当前系统定位manager*/
private LocationManager lm;
/** 位置提供器*/
private String mProvider;
/** 定位change监听*/
private MyLocationListener mChangeListener;
/** 响应用户的回调*/
private ISiLoResponseListener mListener;
/** 服务的参数配置类*/
private SiLoOption mSiLoOption;
/** 当前经纬度*/
private Latlng latlng;
/** 计数器*/
private int mCounter;
/** gps信号消失,尝试network定位*/
private static final int GPS_TIME_SPACE = 6;
/** 尝试network之后,同样获取不到定位,则错误回调,时间间隔 = 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;
}
@Override
public void start(@Nullable ISiLoResponseListener listener) {
if(listener != null)
this.mListener = listener;
if(mListener == null)
return;
lm = (LocationManager) mContext.getApplicationContext()
.getSystemService(Context.LOCATION_SERVICE);
// 检查是否有相关定位权限
if(!Helper.checkPermission(mContext.getApplicationContext())){
mListener.onFail(“location no permission”);
return;
}
// 如果不传配置类,则按默认配置
if(mSiLoOption == null)
mSiLoOption = new SiLoOption();
mProvider = mSiLoOption.isGpsFirst ? Helper.getGPSProvider(lm) : Helper.getNetWorkProvider(lm);
if(mProvider == null)
mListener.onFail(“location provider no exist”);
else
getLocation(mProvider);
}
@Override
public void reStart() {
start(null);
}
@Override
public 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 {
@Override
public 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无信号时,尝试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){
// 只要最后一个net点失败,就抛出回调;前两个点,由于开始,可能为空,不做强制判断处理
mListener.onFail("location latlng = null , provider = "+ mProvider);
}
}
}else{
// 当network获取不到定位
if(location == null)
mListener.onFail("location latlng = null , provider = "+ mProvider);
}
}
@Override
public 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;
}
}
}
@Override
public void onProviderEnabled(String s) {
}
@Override
public void onProviderDisabled(String s) {
}
}
public static class SiLoOption {
/**
- gps 优先否
*/
private boolean isGpsFirst = false;
/**
- 监听定位变化最短时间间隔,默认time s
*/
private int time = 2000;
/**
- 监听变化的最小距离
*/
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;
}
}
}
获取经纬度代码:定位类
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;
// 默认使用sn校验方式
private boolean isSn = true;
private MyAsyncTask task;
private IReGeListener mListener;
@Override
public void init(@Nullable Context context) {
paramsMap = new LinkedHashMap<>();
paramsMap.put(“ak”, ak);
paramsMap.put(“coordtype”, “wgs84ll”);
}
@Override
public 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();
}
@Override
public 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();
}
@Override
public void stop() {
if(paramsMap != null)
paramsMap.clear();
paramsMap = null;
task = null;
}
@Override
public void addReGeListener(IReGeListener listener) {
mListener = listener;
}
class MyAsyncTask extends AsyncTask<Void, Void, String>{
String mUrl;
public MyAsyncTask(String url) {
mUrl = url;
}
@Override
protected String doInBackground(Void… voids) {
return NetUtil.doHttpGet(mUrl);
}
@Override
protected void onPostExecute(String json) {
super.onPostExecute(json);
fromJson(json);
task = null;
}
}
/**
-
对Map内所有value作utf8编码,拼接返回结果
-
@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请求成功标志码
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”;
/**特定经纬度的反向地理编码:*/
import android.content.Context;
import androidx.annotation.Nullable;
import com.mjzuo.location.bean.Latlng;
import com.mjzuo.location.constant.Constant;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
感觉现在好多人都在说什么安卓快凉了,工作越来越难找了。又是说什么程序员中年危机啥的,为啥我这年近30的老农根本没有这种感觉,反倒觉得那些贩卖焦虑的都是瞎j8扯谈。当然,职业危机意识确实是要有的,但根本没到那种草木皆兵的地步好吗?
Android凉了都是弱者的借口和说辞。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。
所以,最后这里放上我耗时两个月,将自己8年Android开发的知识笔记整理成的Android开发者必知必会系统学习资料笔记,上述知识点在笔记中都有详细的解读,里面还包含了腾讯、字节跳动、阿里、百度2019-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。
以上全套学习笔记面试宝典,吃透一半保你可以吊打面试官,只有自己真正强大了,有核心竞争力,你才有拒绝offer的权力,所以,奋斗吧!骚年们!千里之行,始于足下。种下一颗树最好的时间是十年前,其次,就是现在。
最后,赠与大家一句诗,共勉!
不驰于空想,不骛于虚声。不忘初心,方得始终。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-gQzXUiBt-1712014656508)]
[外链图片转存中…(img-IuTbTyqi-1712014656509)]
[外链图片转存中…(img-TGFFjJ7p-1712014656509)]
[外链图片转存中…(img-6ek1zmps-1712014656509)]
[外链图片转存中…(img-WxLEIxWA-1712014656509)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
感觉现在好多人都在说什么安卓快凉了,工作越来越难找了。又是说什么程序员中年危机啥的,为啥我这年近30的老农根本没有这种感觉,反倒觉得那些贩卖焦虑的都是瞎j8扯谈。当然,职业危机意识确实是要有的,但根本没到那种草木皆兵的地步好吗?
Android凉了都是弱者的借口和说辞。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。
所以,最后这里放上我耗时两个月,将自己8年Android开发的知识笔记整理成的Android开发者必知必会系统学习资料笔记,上述知识点在笔记中都有详细的解读,里面还包含了腾讯、字节跳动、阿里、百度2019-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。
[外链图片转存中…(img-Wanju82c-1712014656509)]
以上全套学习笔记面试宝典,吃透一半保你可以吊打面试官,只有自己真正强大了,有核心竞争力,你才有拒绝offer的权力,所以,奋斗吧!骚年们!千里之行,始于足下。种下一颗树最好的时间是十年前,其次,就是现在。
最后,赠与大家一句诗,共勉!
不驰于空想,不骛于虚声。不忘初心,方得始终。