最近一朋友让我了解下安卓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. Linux:文件权限

    使用较长格式列出文件:ls -l显示除了 '.'(当前目录),'..' 上一级目录之外的所有包含隐藏文件(Linux 下以 '.' 开头的文件为隐藏文件): ls -Al查看某一个目录的完整属性,而不 ...

  2. FreeIconMaker - 在线创建免费和时尚的图标

    在设计一个网站或 Web 应用程序时,你不能否认网页设计工具的重要性,这些工具有助于简化您的任务和完成您的项目.FreeIconMaker.com 是一个免费的在线图标制作工具,您也可以创建自己的模板 ...

  3. atitit.提升开发效率---mda 软件开发方式的革命

    atitit.提升开发效率---mda 软件开发方式的革命 1. 软件开发方式的革命开发工具的抽象层次将再次提升 1 2. 应用框架和其实现相分离 2 3. 目前的问题模型和代码不同步 2 4. MD ...

  4. atitit. hb 原生sql跨数据库解决原理 获得hb 数据库类型运行期获得Dialect

    atitit. hb 原生sql跨数据库解决原理 获得hb 数据库类型运行期获得Dialect   #-----原理 Hibernate 运行期获得Dialect   2010-07-28 12:59 ...

  5. EXCEL VBA入门篇之代码应用基础

  6. FreeCodeCamp 高级算法(个人向)

    freecodecamp 高级算法地址戳这里. freecodecamp的初级和中级算法,基本给个思路就能完成,而高级算法稍微麻烦了一点,所以我会把自己的解答思路写清楚,如果有错误或者更好的解法,欢迎 ...

  7. FreeSwitch安装配置记录

    安装FreeSwitch 主要命令如下: git clone -b v1.2.stable git://git.freeswitch.org/freeswitch.gitcd freeswitch/. ...

  8. mybatis中传入String类型参数异常

    在使用mybatis时,写了一条sql语句,只有一个String类型的参数, 示例代码 <select id="getApplyNum" parameterType=&quo ...

  9. Oracle Redo Log 机制 小结(转载)

    Oracle 的Redo 机制DB的一个重要机制,理解这个机制对DBA来说也是非常重要,之前的Blog里也林林散散的写了一些,前些日子看老白日记里也有说明,所以结合老白日记里的内容,对oracle 的 ...

  10. linux系统下重启tomcat的shell脚本

    linux系统下重启tomcat的shell脚本: #!/bin/shtomcat_home=/opt/apache-tomcat- #找到tomcat进程的id并kill掉 ps -ef |grep ...