最近一朋友让我了解下安卓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. SQL——神奇代码1之Update

    说明:一个带有update的循环的代码.很简单,但是在QQ群里问了,应该说是很少有人注意这个问题,也就是很少有人真的理解SQL中的Update. 代码如下: if object_id('tempdb. ...

  2. 菜鸟学习WCF笔记-契约(Contract)

    契约,契约确保了服务的正常调用,客户端以契约的方式进行服务端调用,而服务则需要按照契约规定的方式提供服务. 契约是服务提供的一组操作的描述 功能上讲:每个操作对应着某个具体的功能实现,以及调用这个操作 ...

  3. Leetcode 21 Merge Two Sorted Lists 链表

    合并两个已排序的链表,考到烂得不能再烂的经典题,但是很多人写这段代码会有这样或那样的问题 这里我给出了我的C++算法实现 /** * Definition for singly-linked list ...

  4. php-fpm的配置和优化

    php-fpm的安装目录 下面是我的平时的环境搭建php的各种安装目录,大家的基本也差不多. centos等linux平台 /usr/local/php/php /usr/local/php/etc/ ...

  5. 在线教程的游戏化-20分钟做了个demo

    首先,不准说做得撇,因为其一,我只用了20分钟不到:其二,第一次尝试,以前想过,但是一直没有搞过,二话不说,先来截图,下载地址在最下面. 因为第一次尝试,所以很多事件自己还没有闹明白,不过基本上还是看 ...

  6. SmartThings物联网平台简介

    SmartThings是一个智能设备控制系统,它包括:SmartThings Cloud(云平台).SmartThings Hub(网关).SmartThings Mobile(手机客户端)以及各种关 ...

  7. jquery easyui 插件开发

    (function($) { /** * 插件定义 */ $.fn.resquery = function(options, param) { if (typeof options == " ...

  8. Chrome谷歌浏览器首页被改为Hao123导航怎么办|附各类解决方法【转】

    软件小子:昨天偶然间发现自己的chrome浏览器的首页被篡改成hao123导航了,要是自己设置的还无所谓,但是后面还有尾巴.顿时就火了,又是哪款软件这么流氓,太无良了,我非常确定我肯定是没有勾选什么设 ...

  9. AYUI4.X即将发布

    AYUI里程碑故事: AYUI 1.x系列:   面向源码的方式开发,客户只有源码才能开发,客户端对接ayui,很不方便,相比上个版本,提供了一些元老控件,文件夹结构比较零散 AYUI 2.x系列: ...

  10. 错误名称:EntityCommandExecutionException

    错误名称:EntityCommandExecutionException 错误时间:2015/9/22 11:13:34 错误消息:执行命令定义时出错.有关详细信息,请参阅内部异常. 堆栈信息: 在 ...