最近一朋友让我了解下安卓LBS获取位置信息,于是动手实践了一把。搜了一圈发现有篇博文可以参考:Android那些事儿之LBS定位,但是原文作者没有提供源码下载,于是动手实现了,现记录下来备忘,代码附在后面各位有用得上的直接拿去。

以下是原文的转载:

Android那些事儿之LBS定位

2012-05-24 11:37:00

标签:LBS Android
 
最近为了做LBS功能模块,到网上搜了一些资料,大多数介绍都是使用繁琐的基站定位,要自己去读取什么CellId,LocationAreaCode, MobileCountryCode,MobileNetworkCode等参数,而且多数是针对GSM/UMTS。而自己使用的CDMA,跟上面的参数叫法不一样,还得自己一个一个去对应。虽然最后算是解决了,但是难道就没有更好的办法吗。

翻了翻Android Developer找到一个不错的东西LocationManager。LocationManager是通过listener的方式来告知调用者,而原来写好的模块是直接return的,于是得稍微改造一下:

首先定义一个Model:

  1. public class LocationData {
  2. String lat;
  3. String lon;
  4. String address;
  5. }

然后LBS的所有功能都封装到一个工具类里面:

首先在构造函数里面获取系统服务中的LocationManager:

  1. public class LBSTool {
  2. private Context mContext;
  3. private LocationManager mLocationManager;
  4. private LocationData mLocation;
  5. private LBSThread mLBSThread;
  6. private MyLocationListner mNetworkListner;
  7. private MyLocationListner mGPSListener;
  8. private Looper mLooper;
  9. public LBSTool(Context context) {
  10. mContext = context;
  11. //获取Location manager
  12. mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
  13. }
  14. ......
  15. }

然后是入口方法,这里会启动一个子线程去获取地理位置信息,并让主线程进入等待,时长通过timeout设置

  1. /**
  2. * 开始定位
  3. * @param timeout 超时设置
  4. * @return LocationData位置数据,如果超时则为null
  5. */
  6. public LocationData getLocation(long timeout) {
  7. mLocation = null;
  8. mLBSThread = new LBSThread();
  9. mLBSThread.start();//启动LBSThread
  10. timeout = timeout > 0 ? timeout : 0;
  11. synchronized (mLBSThread) {
  12. try {
  13. Log.i(Thread.currentThread().getName(), "Waiting for LocationThread to complete...");
  14. mLBSThread.wait(timeout);//主线程进入等待,等待时长timeout ms
  15. Log.i(Thread.currentThread().getName(), "Completed.Now back to main thread");
  16. }
  17. catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. mLBSThread = null;
  22. return mLocation;
  23. }

子线程通过调用registerLocationListener开启位置服务的监听,并且讲监听器分配给指定looper

  1. private class LBSThread extends Thread {
  2. @Override
  3. public void run() {
  4. setName("location thread");
  5. Log.i(Thread.currentThread().getName(), "--start--");
  6. Looper.prepare();//给LBSThread加上Looper
  7. mLooper = Looper.myLooper();
  8. registerLocationListener();
  9. Looper.loop();
  10. Log.e(Thread.currentThread().getName(),  "--end--");
  11. }
  12. }
  13. private void registerLocationListener () {
  14. Log.i(Thread.currentThread().getName(), "registerLocationListener");
  15. if (isGPSEnabled()) {
  16. mGPSListener=new MyLocationListner();
  17. //五个参数分别为位置服务的提供者,最短通知时间间隔,最小位置变化,listener,listener所在消息队列的looper
  18. mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, mGPSListener, mLooper);
  19. }
  20. if (isNetworkEnabled()) {
  21. mNetworkListner=new MyLocationListner();
  22. mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 3000, 0, mNetworkListner, mLooper);
  23. }
  24. }

isGPSEnabled和isNetworkEnabled分别为判断当前手机是否开启了GPS以及网络的状况(包含了是否开启wifi和移动网络),以决定使用哪一种服务提供者:GPS_PROVIDER或者NETWORK_PROVIDER。

  1. /**
  2. * 判断GPS是否开启
  3. * @return
  4. */
  5. public boolean isGPSEnabled() {
  6. if(mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
  7. Log.i(Thread.currentThread().getName(), "isGPSEnabled");
  8. return true;
  9. }
  10. else {
  11. return false;
  12. }
  13. }
  14. /**
  15. * 判断Network是否开启(包括移动网络和wifi)
  16. * @return
  17. */
  18. public boolean isNetworkEnabled() {
  19. return (isWIFIEnabled() || isTelephonyEnabled());
  20. }
  21. /**
  22. * 判断移动网络是否开启
  23. * @return
  24. */
  25. public boolean isTelephonyEnabled() {
  26. boolean enable = false;
  27. TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
  28. if (telephonyManager != null) {
  29. if (telephonyManager.getNetworkType() != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
  30. enable = true;
  31. Log.i(Thread.currentThread().getName(), "isTelephonyEnabled");
  32. }
  33. }
  34. return enable;
  35. }
  36. /**
  37. * 判断wifi是否开启
  38. */
  39. public boolean isWIFIEnabled() {
  40. boolean enable = false;
  41. WifiManager wifiManager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
  42. if(wifiManager.isWifiEnabled()) {
  43. enable = true;
  44. Log.i(Thread.currentThread().getName(), "isWIFIEnabled");
  45. }
  46. return enable;
  47. }

当LocationManager在大于最短时间且检测到最小位置变化时,就会通知给监听器,然后我们就可以通过返回的经纬度信息去google服务器查找对应的地址,然后停止LocationManger的工作,解除LBSThread中的Looper,让LBSThread结束,最后通知主线程可以继续,整个流程结束。

  1. private class MyLocationListner implements LocationListener{
  2. @Override
  3. public void onLocationChanged(Location location) {
  4. // 当LocationManager检测到最小位置变化时,就会回调到这里
  5. Log.i(Thread.currentThread().getName(), "Got New Location of provider:"+location.getProvider());
  6. unRegisterLocationListener();//停止LocationManager的工作
  7. try {
  8. synchronized (mLBSThread) {
  9. parseLatLon(location.getLatitude()+"", location.getLongitude()+"");//解析地理位置
  10. mLooper.quit();//解除LBSThread的Looper,LBSThread结束
  11. mLBSThread.notify();//通知主线程继续
  12. }
  13. }
  14. catch (Exception e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. //后3个方法此处不做处理
  19. @Override
  20. public void onStatusChanged(String provider, int status, Bundle extras) {}
  21. @Override
  22. public void onProviderEnabled(String provider) {}
  23. @Override
  24. public void onProviderDisabled(String provider) {}
  25. };
  26. /**
  27. * 使用经纬度从goole服务器获取对应地址
  28. * @param 经纬度
  29. */
  30. private void parseLatLon(String lat, String lon) throws Exception {
  31. Log.e(Thread.currentThread().getName(),  "---parseLatLon---");
  32. Log.e(Thread.currentThread().getName(),  "---"+lat+"---");
  33. try {
  34. HttpClient httpClient = new DefaultHttpClient();
  35. HttpGet get = new HttpGet("http://ditu.google.cn/maps/geo?output=json&q="+lat+","+lon);
  36. HttpResponse response = httpClient.execute(get);
  37. String resultString = EntityUtils.toString(response.getEntity());
  38. JSONObject jsonresult = new JSONObject(resultString);
  39. if(jsonresult.optJSONArray("Placemark") != null) {
  40. mLocation = new LocationData();
  41. mLocation.lat = lat;
  42. mLocation.lon = lon;
  43. mLocation.address = jsonresult.optJSONArray("Placemark").optJSONObject(0).optString("address");
  44. }
  45. }
  46. catch (Exception e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. /**
  51. * 注销监听器
  52. */
  53. private void unRegisterLocationListener () {
  54. if(mGPSListener!=null){
  55. mLocationManager.removeUpdates(mGPSListener);
  56. mGPSListener=null;
  57. }
  58. if(mNetworkListner!=null){
  59. mLocationManager.removeUpdates(mNetworkListner);
  60. mNetworkListner=null;
  61. }
  62. }

接下来可以在界面上安放个button:

  1. locationBtn.setOnClickListener(new OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. //return mode
  5. LBSTool lbs = new LBSTool(LBStestActivity.this);
  6. LocationData location = lbs.getLocation(120000);
  7. if (location != null) {
  8. Log.i("---lat---",location.lat);
  9. Log.i("---lon---",location.lon);
  10. Log.i("---address---",location.address);
  11. Toast.makeText(LBStestActivity.this, location.lat + " " + location.lon + " " + location.address, Toast.LENGTH_LONG).show();
  12. }
  13. }
  14. });

最后别忘了加入权限:

  1. <uses-permission android:name="android.permission.INTERNET" />
  2. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  3. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
  4. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  5. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

此外,LocationManager还有些高级的用法,比如设置一些关键参数,以及获取最后一次定位信息等等:

  1. Criteria criteria = new Criteria();
  2. criteria.setAccuracy(Criteria.ACCURACY_FINE); // 高精度
  3. criteria.setAltitudeRequired(false);
  4. criteria.setBearingRequired(false);
  5. criteria.setCostAllowed(true);
  6. criteria.setPowerRequirement(Criteria.POWER_LOW); // 低功耗
  7. String bestprovider = locationManager.getBestProvider(criteria, true); // 获取GPS信息
  8. Location location = locationManager.getLastKnownLocation(bestprovider); // 通过GPS获取位置
  9. Log.e("--bestprovider--", bestprovider);
  10. Log.e("--bestprovider--", location.getLatitude()+"");

本文出自 “Android那些事儿” 博客,请务必保留此出处http://winwyf.blog.51cto.com/4561999/875617

问题:

google api 过时了,google中国退出后, 这种方式:"HttpGet get = new HttpGet("http://ditu.google.cn/maps/geo?output=json&q="+lat+","+lon); "取不到地址信息了。

解决方法:

http://maps.google.com/maps/api/geocode/json?latlng="  + lat + "," + lon + "&language=zh-CN&sensor=false

效果:

源码

这是源码。

Android那些事儿之LBS定位,实践测试lbs的更多相关文章

  1. Android之仿ele地图定位效果

    PS:最近项目要求,希望在选择地址的时候能够仿ele来实现定位效果.因此就去做了一下.不过ele使用高德地图实现的,我是用百度地图实现的.没办法,公司说用百度那就用百度的吧.个人觉得高德应该更加的精准 ...

  2. 实现Android的不同精度的定位(基于网络和GPS)

    解决方案: 实现Android的不同精度的定位(基于网络和GPS) Android中的定位服务的相关类基本上都在android.location包中,其中位置服务管理器(LocationManager ...

  3. LBS定位技术

    http://www.cnblogs.com/LBSer/p/3295642.html LBS定位技术从方法上可分成三类:基于三角关系的定位技术.基于场景分析的定位技术.基于临近关系的定位技术(唐毅和 ...

  4. android 高德地图出现【定位失败key鉴权失败】

    如题:android 高德地图出现[定位失败key鉴权失败] 原因:使用的是debug模式下的SHA1,发布的版本正确获取SHA1的方式见: 方法二使用 keytool(jdk自带工具),按照如下步骤 ...

  5. 【Android Api 翻译1】Android Texting(2)Testing Fundamentals 测试基础篇

    Testing Fundamentals The Android testing framework, an integral part of the development environment, ...

  6. Android 设计随便说说之简单实践(合理组合)

    上一篇(Android 设计随便说说之简单实践(模块划分))例举了应用商店设计来说明怎么做模块划分.模块划分主要依赖于第一是业务需求,具体是怎么样的业务.应用商店则包括两个业务,就是向用户展示appl ...

  7. 在Android Studio中进行单元测试和UI测试

    本篇教程翻译自Google I/O 2015中关于测试的codelab,掌握科学上网的同学请点击这里阅读:Unit and UI Testing in Android Studio.能力有限,如有翻译 ...

  8. Android Texting(2)Testing Fundamentals 测试基础篇

    Testing Fundamentals The Android testing framework, an integral part of the development environment, ...

  9. Android系统中是否开启定位及定位模式的判断

    1.关于Android系统中不同的定位模式 Android系统中包括3中定位模式:   使用GPS.WLAN和移动网络 使用WLAN和移动网络 仅使用GPS 截图 特点 同时使用GPS.WIFI及基站 ...

随机推荐

  1. [汇编] 将字符串里的一个'&'字符换成空格

    ; multi-segment executable file template. data segment ; add your data here! pkey db "press any ...

  2. 小米Web前端JavaScript面试题

    面试题目 一. 请定义这样一个函数 function repeat (func, times, wait) { } 这个函数能返回一个新函数,比如这样用 var repeatedFun = repea ...

  3. Spring声明式事务配置与使用

    1.配置: <context:component-scan base-package="com.vrvwh.wh01" /><bean id="data ...

  4. iOS YSKit系列

    YSKit是基于object-c的一套常用功能点的总结,都是我们在平时开发的过程中遇到的.这个框架将会慢慢地完善,由于本人精力有限,有时可能更新得相对慢一点.如果发现代码里有错误,也欢迎提出. 1.常 ...

  5. 使用TabBarController(代码实现)

    step01:使用Xcode创建一个项目 step02:填写项目必要信息 step03:检查文件结构树是否正确 step04:创建一些类,这些类将会在后面用到!(选择Swift File) step0 ...

  6. paip.判断文件是否存在uapi python php java c#

    paip.判断文件是否存在uapi python php java c# ==========uapi file_exists exists() 面向对象风格:  File.Exists 作者: 老哇 ...

  7. 教你轻松看懂 iOS9 新功能

    2015苹果全球开发者大会在6月9日凌晨,美国旧金山举行,fir.im 整理了一部分的资料,帮助了解 iOS9 的新特性与功能,感兴趣的可以看下. 关于iOS9新增功能 在WWDC 2015上苹果介绍 ...

  8. Django模板系统

    创建模板对象Template类在django.template模板中 // 用django-admin.py startproject 命令创建一个项目目录django-admin.py startp ...

  9. Android 代理服务器为全网提供代理

    Android 代理服务器为全网提供代理 背景:学校WiFI过滤较严,故学生很少有可以上网账号的.而学校又分为俩层验证,第一层可以注册并且拥有访问校内网的权限,第二层为校内密码验证机(非服务器)进行用 ...

  10. 解决中64位Win7系统上PLSQL无法连接ORACLE的方法(PLSQL无法识别ORACLE_HOME的配置)

    最近新安装了64位的Win7系统,工作中需要用oracle数据库,而数据库是公司IT的DBA进行管理和维护的. 我们只需要连接上去进行使用就可以了,于是我就在自己的机器上安装了oracle clien ...