zoukankan      html  css  js  c++  java
  • Android之实现定位

    基于android的定位无非就两种:network、gps。两者各有优劣。

    Network:定位快,准确度低,受环境影响小。

    GPS:定位慢,准确度高,受环境影响大。


    本文要解决的问题:

    1.      locationManager.getLastKnownLocation方法返回null。

    2.      如何实现快速而又精确的定位。

     

    E文好的话,直接看官网就好了http://developer.android.com/guide/topics/location/strategies.html

     

    在你的程序里如果有这样的代码你就要注意了(现在看来这些倒是多余了)

    <span style="font-size:14px;">    Criteria criteria = new Criteria();  
                criteria.setAccuracy(Criteria.ACCURACY_FINE);//高精度  
                criteria.setAltitudeRequired(false);//无海拔要求  
                criteria.setBearingRequired(false);//无方位要求  
                criteria.setCostAllowed(true);//允许产生资费  
                criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗  
                
                // 获取最佳服务对象  
                String provider = locationManager.getBestProvider(criteria,true);  
        locationManager.getLastKnownLocation(provider);  </span>


    locationManager.getBestProvider(criteria,true);方法看起来很完美,但其实返回值就network、gps二选一。而且如果你要求高精度,它会优先检查GPS,如果手机开启了GPS就返回GPS,否则返回network。如果都没开启则返回null。

    结合Network、GPS两种定位方式的优劣不难看出为什么getLastKnownLocation方法会返回null(这只针对第一次定位)。

     

    当你开启GPS,provider的值为GPS。这时的定位方式为GPS,由于GPS定位慢(我测试的时间大约为50秒),所以它不可能立即返回你一个Location对象,所以就返回null了。还有人用下面的方法解决这个问题:

    <span style="font-size:14px;">    while (location ==null) {  
               location = locationManager.getLastKnownLocation(provider);  
           }  </span>


    这绝对是个愚蠢的做法!举个例子:如果你在室内,gps无法定位到,你的程序将陷入死循环。当然使用requestLocationUpdates可以做到定位且不让程序陷入死循环,但是定位耗时长,甚至得不到定位。

    如果使用网络定位呢,不得说这也是一个不错的选择。locationManager.requestLocationUpdates(

                  LocationManager.NETWORK_PROVIDER, 0, 0,networkListener);

    网络定位耗时一般在2秒左右(网络差,时间会更长),只要你接入网络,基本上都能获得定位。唯一的缺点就是精度不高。

     

    那能不能将两者结合,这也是本文的重点。既然结合两者,就要同时为两者添加监听

    <span style="font-size:14px;">    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000 * 2,50,gpsListener);  
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,networkListener);  </span>


    这样,大概2秒我们就可以得到来自网络的定位,一分钟后得到来自GPS定位。这时用GPS定位替换网络定位就好了。当然这只是个理想的情况,现实要复杂的多。

    比如:

    你第一次定位成功返回location,由于网络问题第二次返回null。这时会发现,更新的location没有上次的精确,甚至是null,无法使用,这时我们要判断当前的location和新获得的location那个更好。可能你获得GPS定位后,由于天气、进入隧道等原因GPS服务器丢失,无法更新location(这时一个好的做法是切换到network定位)。还有可能用户没有开启GPS和network,根本就谈不上定位(其实每次定位成功都会有个定位缓存的,可以使用getLastKnownLocation获得)。

     

    终上所述,我们要做的就是:

    1.  尝试通过getLastKnownLocation获取上次定位信息

    2.  开启network和gps监听

    3.  获得network定位信息location

    4.  比较当前location和新获取的location哪个更好(来自network)

    5.  获得gps定位信息location

    6.  停掉network监听

    7.  比较当前location和新获取的location哪个更好(来自gps)

    8.  如果gps服务器丢失,重新开启network监听


    以GPS监听为例

    <span style="font-size:14px;">    // GPS监听的回调函数  
         private class GPSLocationListener implements LocationListener {  
          
            private boolean isRemove = false;//判断网络监听是否移除  
          
            @Override  
            public void onLocationChanged(Location location) {  
                // TODO Auto-generatedmethod stub  
                boolean flag =betterLocation.isBetterLocation(location,  
                       currentBestLocation);  
          
                if (flag) {  
                   currentBestLocation = location;  
                   updateLocation(currentBestLocation);  
                }  
                // 获得GPS服务后,移除network监听  
                if (location !=null && !isRemove) {  
                   locationManager.removeUpdates(networkListener);  
                   isRemove = true;  
                }  
            }  
          
            @Override  
            public void onProviderDisabled(String provider) {  
                // TODO Auto-generatedmethod stub  
            }  
          
            @Override  
            public void onProviderEnabled(String provider) {  
                // TODO Auto-generatedmethod stub  
            }  
          
            @Override  
            public void onStatusChanged(String provider, int status, Bundleextras) {  
                // TODO Auto-generatedmethod stub  
                if (LocationProvider.OUT_OF_SERVICE == status) {  
                   Toast.makeText(MainActivity.this,"GPS服务丢失,切换至网络定位",  
                          Toast.LENGTH_SHORT).show();  
                   locationManager  
                          .requestLocationUpdates(  
                                 LocationManager.NETWORK_PROVIDER, 0, 0,  
                                 networkListener);  
                }  
            }  
         }  </span>


    其中isBetterLocation是用来判断哪个location更好的。这个方法来自android官网的,通过location获取的时间,精度等信息进行判断。

    因为之前上传的demo,大家觉得意义不大,所以就不再提供了。

    下图的‘微秒’单位错了,应该是毫秒


    后来我接触的项目中对定位的要求发现并不是那么高,只是需要简单的获取到当前位置就够了,而且只是在每次启动时获取一次。

    Android简单定位的实现可以参见http://blog.csdn.net/limb99/article/details/18819925


    from:http://blog.csdn.net/limb99/article/details/8765584#comments

    关注公众号,分享干货,讨论技术


  • 相关阅读:
    sql sever读取写入Excel总结
    sql sever跨数据库复制数据的方法
    SQLServer2005重建索引前后对比【转】
    SQL自定义函数
    【C】——回调函数实现泛型算法
    【C】——压缩字符串
    【C】——指针与const限定符
    loop within fields
    分类与分步在行测数量关系中的应用
    隔年增长率
  • 原文地址:https://www.cnblogs.com/molashaonian/p/9097665.html
Copyright © 2011-2022 走看看