>>分享Android开发相关的技术 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 19371 个阅读者 刷新本主题
 * 贴子主题:  Android那些事儿之LBS定位 回复文章 点赞(0)  收藏  
作者:sunshine    发表时间:2020-03-31 17:25:48     消息  查看  搜索  好友  邮件  复制  引用

   最近为了做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()+ "" );    

               ----------------------------
原文链接:https://blog.51cto.com/winwyf/875617

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-04-17 12:34:41 重新编辑]
  Java面向对象编程-->输入与输出(上)
  JavaWeb开发-->使用Session(Ⅰ)
  JSP与Hibernate开发-->数据库事务的概念和声明
  Java网络编程-->非阻塞通信
  精通Spring-->虚拟DOM和render()函数
  Vue3开发-->通过Axios访问服务器
  android webView js方法和java 方法交互-android,unity3d
  如何提高Android代码的安全性
  Android ListView高度问题
  Android UI学习 - TableLayout
  Android多屏幕适配
  创建 和使用Android服务
  从Android中Activity之间的通信说开来
  android 如何监听自身应用被卸载
  Android 4.0 : 复制APK,复制动态库的Android.mk 文件
  Android数据存储之Content Providers
  Android 性能优化之渲染原理
  android 自定义view 实现定制二维码扫描框
  Android 资源(Resources)管理
  程序员笔记|JSBridge框架解决通信问题实现移动端跨平台开发
  MVVM 架构与数据绑定库
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。