最近一朋友让我了解下安卓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. [游戏学习26] MFC 时间函数 画图形

    >_<:这里第一次介绍MFC的时间函数,功能和Win32里的计时器类似. >_<:这里还介绍了MFC的图形绘制函数,和Win32有一点区别 >_<:ABC.h #d ...

  2. Node.js 爬虫,自动化抓取文章标题和正文

    持续进行中... 目标: 动态User-Agent模拟浏览器 √ 支持Proxy设置,避免被服务器端拒绝 √ 支持多核模式,发挥多核CPU性能 √ 支持核内并发模式 √ 自动解码非英文站点,避免乱码出 ...

  3. 解析json实例

    解析项目目录中的一个json文件,将之转化为List的一个方法. package com.miracles.p3.os.util; import com.miracles.p3.os.mode.Vid ...

  4. [读书笔记]C#学习笔记二: 委托和事件的用法及不同.

    前言:  C#委托是什么 c#中的委托可以理解为函数的一个包装, 它使得C#中的函数可以作为参数来被传递, 这在作用上相当于C++中的函数指针. C++用函数指针获取函数的入口地址, 然后通过这个指针 ...

  5. css伪元素选择器

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. Django博客功能实现

    开发环境:Python3.5.2和Django1.10.2 username: rootemail: 2016968116@qq.compassword: 123456liuqiuchen 现在我们进 ...

  7. JQ属性和css部分测试

    1.attr(name|properties|key,value|fn)  设置或返回被选元素的属性值. <div class="attr">设置或返回被选元素的属性值 ...

  8. Revit API 获取某墙上洞口的尺寸和位置

    [Transaction(TransactionMode.Manual)] [Regeneration(RegenerationOption.Manual)] public class cmd2012 ...

  9. Java 命名空间的由来和引入

    名字可视性(Name visibility) 名字管理对任何程序设计语言来说,都是一个重要问题.如果你在程序的某个模块里使用了 一个名字,而其他人在这个程序的另一个模块里也使用了相同的名字,那么怎样才 ...

  10. 推荐几款API文档集合工具

    https://zealdocs.org/    开源.免费,支持Linux.Windows http://velocity.silverlakesoftware.com/  https://kape ...