Android中的getLastKnowLocation空指针异常

来源:互联网 发布:js数据类型 编辑:程序博客网 时间:2024/05/09 09:17

这个问题也困扰我很久,为什么之前用模拟器测试有时可以成功有时却失败,而使用真机测试却从来没有成功,很是郁闷

首先大家应该记得下面一段代码的作用:

view plain
  1. //设置服务商的信息  
  2.        Criteria criteria =new Criteria();  
  3.        //提供服务的精度标准  
  4.        criteria.setAccuracy(Criteria.ACCURACY_FINE);  
  5.        //不需要高度信息  
  6.        criteria.setAltitudeRequired(false);  
  7.        //不需要方位信息  
  8.        criteria.setBearingRequired(false);  
  9.        //不允许产生费用  
  10.        criteria.setCostAllowed(false);  
  11.        //消耗电力为低  
  12.        criteria.setPowerRequirement(Criteria.POWER_LOW);  
  13.        //取得最匹配的criteria  
  14.        //best_provider=mlocationManager.getBestProvider(criteria, true);  
 

通过上面的程序我们获得了最佳的服务提供方式,可是经过我多次实验发现每次获得的最佳提供者都是GPS方式,这就意味之后我们操作获取位置时使用过GPS方式获取的,那么接着我们通常是如下面方式获取位置的

view plain
  1. //得到之前获得的坐标相关的信息  
  2.         mLocation=mlocationManager.getLastKnownLocation(best_provider);           
  3.         //得到地址编码,用于后面查找当前地址名称  
  4.         mGeocoder = new Geocoder(this,Locale.getDefault());  
  5.         //更新位置信息  
  6.         updateLocation(mLocation);      
  7.         //创建LocationManager对象,监听位置更改事情,并更新MapView  
  8.         mlocationManager.requestLocationUpdates(best_provider,6000,100,mLocationListener);  

view plain
  1. //更新定位  
  2.     public void updateLocation(Location location)   
  3.     {  
  4.         if( location == null )  
  5.         {  
  6.             return;  
  7.             //mlocationManager.requestLocationUpdates(best_provider,60000,1,mLocationListener);  
  8.         }  
  9.         //设置使用LocationOverlay来绘制当前位置  
  10.         mLocationOverlay=new LocationOverlay(this);  
  11.         List<Overlay> overlays=mMapView.getOverlays();  
  12.         overlays.add(mLocationOverlay);  
  13.         //绘制当前位置  
  14.         mLocationOverlay.setLocation(location);  
  15.         //当前经纬度  
  16.         Double geoLat=location.getLatitude()*1E6;  
  17.         Double geoLng=location.getLongitude()*1E6;  
  18.         //将其转换为GeoPoint型  
  19.         GeoPoint point=new GeoPoint(geoLat.intValue(),geoLng.intValue());  
  20.         //动态定位到指定坐标  
  21.         mMapController.animateTo(point);  
  22.     }  
  23.       
  24.     //设置位置监听器     
  25.     private final LocationListener mLocationListener=new LocationListener()  
  26.     {  
  27.         //当位置发生变化时更新  
  28.         public void onLocationChanged(Location location)  
  29.         {  
  30.             updateLocation(location);  
  31.         }  
  32.         //当Provider不可用时,比如GPS没有开启  
  33.         public void onProviderDisabled(String provider)  
  34.         {  
  35.             updateLocation(null);  
  36.         }  
  37.         //当Provider启用时,比如GPS开启  
  38.         public void onProviderEnabled(String provider){}  
  39.         //当Provider的状态改变时,比如在可以,暂时不可以用,关闭之间切换时  
  40.         public void onStatusChanged(String provider,int status,Bundle extras){}  
  41.     };  
 

注意上面的getLastKnownLocation方法,这个方法的意思是获取上一次知道的位置,这里问题是如果我们是第一次启动这个程序,那么上一次的位置是多少呢?我也很纳闷

我们知道在模拟器里面是使用geo fix 122 22这样的命令来模拟当前的位置的,我发现每次模拟位置的时候,第一次启动程序都会出错,而后面启动才获取到了位置,这也许就是那个方法的弊端吧,不知道自己有没有理解错误。

 

那么在真机上测试,这样行的通吗?和可惜,每次启动真机程序使用GPS来定位的时候,GPS模块已经打开,使用其他定位软件也可以找到当前的位置,可是自己写的那个程序却不能获取到位置。

参考网友的建议如:

view plain
  1. while(location  == null)    
  2. {    
  3.   mlocationManager.requestLocationUpdates("best_provider"600001, locationListener);    
  4. }    
 

 

有网友写了下面的程序来替代上面的循环:

view plain
  1.  /**  
  2.     * 这里一定要对LocationManager进行重新设置监听  
  3.     * mgr获取provider的过程不是一次就能成功的  
  4.     * mgr.getLastKnownLocation很可能返回null  
  5.     * 如果只在initProvider()中注册一次监听则基本很难成功  
  6.     */    
  7. @Override    
  8. protected void onResume() {    
  9.     super.onResume();    
  10.     mgr.requestLocationUpdates(bundle.getString("provider"), 600001, locationListener);    
  11. }    
  12.     
  13. @Override    
  14. protected void onPause() {    
  15.     super.onPause();    
  16.     mgr.removeUpdates(locationListener);    
  17. }    
 

上面的程序通过不断判断位置是否为空,直到获取到位置为止,他的解释是getLastKnownLocation一次不能成功,需要多次才能获取到,这刚好验证了我的猜想,之前每次第一次启动都不能成功的情况。可是我的那样做了除了一直循环外还是没有得到位置。

 

直到看到一个国外网页上这样获取位置,才知道是前面的那段服务提供的筛选条件使得我每次获取位置提供者的时候得到的结果都是GPS服务,而这样的方式并不见得好,后来我干脆把服务获取方式写成了直接使用网络方式获取

view plain
  1. best_provider=mlocationManager.NETWORK_PROVIDER;  
  2.         //得到之前获得的坐标相关的信息  
  3.         mLocation=mlocationManager.getLastKnownLocation(best_provider);   
 

事实证明问题就出在位置服务获取方式上,改成使用网络方式后可以在真机上获取到当前位置。

 

那么我写的程序终于可以在真机上跑起来了,贴张图看看,呵呵

上面文字显示没有找到地址是因为网速的问题,本来应该通过地址编码找到相关位置的信息的,这是我做的一个小程序,使用Google Map API开发的,完成了些基本的地图功能,可以在上面做许多扩展的,目前LBS服务很火爆,什么UC乐园,大众点评,网易八方,街旁等,国外还有著名的foursquare,希望与有这方面兴趣的朋友一起学习交流。

 

下面是从国外网站上摘取的,解释getLastKnownLocation的使用方法:

 

The call to request update for a location is not blocking, hence it wont wait there. Also the provider in emulator may not have been started.

A possible check could be to see if the settings in it disable gps provider ? then send geo fix.

However, I would use Location Listener, it would be ideal in your case since you need a geo fix to proceed further.Location Listener is Used for receiving notifications from the LocationManager when the location has changed. You can unregister the listener after first geofix.

Note: It can take some time on device to get current location, and even on device this can return null.

 

 

下面是两个国外描述这方面问题的网页:

http://marakana.com/forums/android/examples/42.html

http://stackoverflow.com/questions/1608632/android-locationmanager-getlastknownlocation-returns-null