• Android那些事儿之LBS定位,实践测试lbs


    最近一朋友让我了解下安卓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.       
    10.     public LBSTool(Context context) {  
    11.         mContext = context;  
    12.         //获取Location manager  
    13.         mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);  
    14.     }  
    15.   
    16. ......  
    17. }  

     然后是入口方法,这里会启动一个子线程去获取地理位置信息,并让主线程进入等待,时长通过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.       
    12.     synchronized (mLBSThread) {  
    13.         try {  
    14.             Log.i(Thread.currentThread().getName(), "Waiting for LocationThread to complete...");  
    15.             mLBSThread.wait(timeout);//主线程进入等待,等待时长timeout ms  
    16.             Log.i(Thread.currentThread().getName(), "Completed.Now back to main thread");  
    17.         }  
    18.         catch (InterruptedException e) {  
    19.             e.printStackTrace();  
    20.         }  
    21.     }  
    22.     mLBSThread = null;  
    23.     return mLocation;  

    子线程通过调用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. }  
    14.   
    15. private void registerLocationListener () {  
    16.     Log.i(Thread.currentThread().getName(), "registerLocationListener");          
    17.     if (isGPSEnabled()) {  
    18.         mGPSListener=new MyLocationListner();    
    19.   
    20.         //五个参数分别为位置服务的提供者,最短通知时间间隔,最小位置变化,listener,listener所在消息队列的looper  
    21.         mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 50000, mGPSListener, mLooper);    
    22.     }  
    23.     if (isNetworkEnabled()) {  
    24.         mNetworkListner=new MyLocationListner();    
    25.  
    26.         mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 30000, mNetworkListner, mLooper);    
    27.     }  

     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. /**  
    16.  * 判断Network是否开启(包括移动网络和wifi)  
    17.  * @return  
    18.  */  
    19. public boolean isNetworkEnabled() {  
    20.     return (isWIFIEnabled() || isTelephonyEnabled());   
    21. }  
    22.   
    23. /**  
    24.  * 判断移动网络是否开启  
    25.  * @return  
    26.  */  
    27. public boolean isTelephonyEnabled() {  
    28.     boolean enable = false;  
    29.     TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);  
    30.     if (telephonyManager != null) {  
    31.         if (telephonyManager.getNetworkType() != TelephonyManager.NETWORK_TYPE_UNKNOWN) {  
    32.             enable = true;  
    33.             Log.i(Thread.currentThread().getName(), "isTelephonyEnabled");  
    34.         }  
    35.     }  
    36.       
    37.     return enable;  
    38. }  
    39.   
    40. /**  
    41.  * 判断wifi是否开启  
    42.  */  
    43. public boolean isWIFIEnabled() {  
    44.     boolean enable = false;  
    45.     WifiManager wifiManager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);  
    46.     if(wifiManager.isWifiEnabled()) {  
    47.         enable = true;  
    48.         Log.i(Thread.currentThread().getName(), "isWIFIEnabled");   
    49.     }   
    50.     return enable;  

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

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

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

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

    最后别忘了加入权限:

    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.          
    8.         String bestprovider = locationManager.getBestProvider(criteria, true); // 获取GPS信息 
    9.         Location location = locationManager.getLastKnownLocation(bestprovider); // 通过GPS获取位置 
    10.         Log.e("--bestprovider--", bestprovider); 
    11.         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

    效果:

    源码

    这是源码。

  • 相关阅读:
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
  • 原文地址:https://www.cnblogs.com/datacool/p/datacool_LBS_Android.html
Copyright © 2020-2023  润新知