前言
定位是社交APP 中能够实时定位社交圈中各个成员的位置 后台实时上传位置则是非常重要的一个技术点
需求
1. 如果用户的位置在持续变化 则隔一段时间上报一次;
2. 如果用户的移动速度很慢 则隔一段距离上报一次;
3. 如果用户的位置在到达某处后没有变化 则不继续上报;
4. 切换到后台也要能定位上报;
准备
先去百度官网下载集成相应的sdk
http://lbsyun.baidu.com/
ios 的 可以 直接戳这里 http://www.cocoachina.com/ios/20150724/12735.html
个人理解IOS与Android不同的是 ios减少耗流量是监听GPS来确定是否移动位置来请求定位;
anderoid 端的 因为没法强制用户一直打开GPS (开GPS 具体耗电量与耗流量参数
http://lbsyun.baidu.com/index.php?title=android-yingyan/guide/consumption)
Android 用户在百度定位api上暂时没有返回速度(GPS未开启时)但是百度官网给我们提供了一个计算距离工具;
public class DistanceUtil {
public DistanceUtil() {
}
/**
*注释:此方法是百度地图计算工具类里面带的
*LatLng var0 第一次定位经纬度
*LatLng var1 最新定位经纬度
*return 两者之间的距离 单位(米)
*/
public static double getDistance(LatLng var0, LatLng var1) {
if(var0 != null && var1 != null) {
Point var2 = CoordUtil.ll2point(var0);
Point var3 = CoordUtil.ll2point(var1);
return var2 != null && var3 != null?CoordUtil.getDistance(var2, var3):-1.0D;
} else {
return -1.0D;
}
}
}
所以我暂时能想到的就是写一个定时器放在服务上并设置5秒获取一次定位(单次定位耗流量0.3K,大约216K/H)
这里怎么开启定时服务暂时就不黏贴代码了 我就介绍一下怎么实现静态不动时与移动时的逻辑:
首先先写一个Model用来保存上次上传到服务端的数据
public class MapModel implements Serializable { /** * 经度 */ private double longitude; /** * 纬度 */ private double latitude; /** * 位置 */ private String address; /** * 本次时间 */ private Date time; //get set 自己生成下就好了
然后在定位数据请求成功时 去判断两次定位间的距离 并做相应的处理;
/** * 定位监听函数 */ public class MyLocationListenner implements BDLocationListener { //接收异步返回的定位结果 @Override public void onReceiveLocation(BDLocation location) { if (location == null) { Log.i("location:", "获取位置失败"); } else { Log.i("location:", "准备提交数据..."); Log.i("location:", "在时间范围内..."); latitude = location.getLatitude(); longitude = location.getLongitude(); address = location.getAddrStr(); /** *这个地方就是把上传到服务端时 的位置保持到 SharedPreferences 在这里取出来调用 */ MapModel mapModel = (MapModel) AndroidUtil.getValue(LApp.getContext(), "MapModel"); if (null == mapModel) { Log.d("location:","刚打开程序上传一次"); saveMapInfo(); } else { if (0.0 == mapModel.getLatitude() || 0.0 == mapModel.getLongitude()) { Log.d("location:","信息错误上传一次"); saveMapInfo(); } else { double distance = DistanceUtil.getDistance( getLatLng(mapModel.getLatitude(), mapModel.getLongitude()), getLatLng(latitude, longitude)); if (distance > 100) { Log.d("location:","大于100米上传一次"); saveMapInfo(); }else { try { //s 是时间差 String s = TimeUtil.hoursBetween(mapModel.getTime(), new Date()); int i = Integer.parseInt(s); //当时间差大于1小时时上传一次位置 然后重置时间 if (i>0){ saveMapInfo(); } } catch (ParseException e) { Log.d("location:","小于100米不上传"+e); e.printStackTrace(); } Log.d("location:","小于100米不上传"); } } } } } @Override public void onConnectHotSpotMessage(String s, int i) { } //接收异步返回的POI查询结果 public void onReceivePoi(BDLocation poiLocation) { if (poiLocation == null) { return; } } }
/** * 解析地图坐标 * * @param latitude * @param longitude * @return */ private LatLng getLatLng(double latitude, double longitude) { return new LatLng(latitude, longitude); } /** * 保存位置信息 并上传到服务端 */ private void saveMapInfo(){ MapModel mapModelSave = new MapModel(); mapModelSave.setLatitude(latitude); mapModelSave.setLongitude(longitude); mapModelSave.setAddress(address); mapModelSave.setTime(new Date()); AndroidUtil.setValue(LApp.getContext(), "MapModel", mapModelSave); upLoadData();//上传数据 }
/** * 计算两个日期之间相差的小时数 * @param smdate 较小的时间 * @param bdate 较大的时间 * @return 相差时间 * @throws ParseException */ public static String hoursBetween(Date smdate,Date bdate) throws ParseException{ SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm"); smdate=sdf.parse(sdf.format(smdate)); bdate=sdf.parse(sdf.format(bdate)); Calendar cal = Calendar.getInstance(); cal.setTime(smdate); long time1 = cal.getTimeInMillis(); cal.setTime(bdate); long time2 = cal.getTimeInMillis(); long between_days=(time2-time1)/(1000*3600); return String.valueOf(between_days); }
好了 上面就是Android端一个简单 的根据时间以及位置移动来上传位置的方案
方案不是很完美 希望大家多多指出不足之处