2012-07-27 41 views
0

我有一个类LocationHelper,我正在设计获取用户位置。在创作时,我指定了所需的准确性,以及位置的当前状态。如果它必须是新获得的位置,或者最近没有足够的前一个位置,那么我想要开始收听位置管理器的更新。我的问题是,我希望这种情况发生在其中一种方法中,并且在找到足够精确的位置之前不会返回该方法。我如何阻止方法返回,直到我找到我想要的位置?我只使用后台服务中的LocationHelper类,所以我不在乎需要很长时间才能返回。 我想过在返回之前放置一个while循环,它检查位置是否为空(直到找到足够精确的位置),如果是,那么它会执行一个等待,但是我正确地认为这是会阻止听众接收更新?如何使方法在返回之前等待足够精确的位置?

如果我的解释不够清楚(我的问题与getCurrentFix,底部),下面的代码,谢谢。

package com.s0812532.AutoBagger; 

import java.util.Date; 

import android.content.Context; 
import android.location.Location; 
import android.location.LocationListener; 
import android.location.LocationManager; 
import android.os.Bundle; 
import android.os.Handler; 


/** 
* Class LocationHelper 
* Class for obtaining the user's location. Capable of obtaining the current 
* position, or the most recent fix available fix without getting a new one, in 
* order to conserve battery power. Will automatically decide whether to use 
* GPS/network based on required accuracy. Must not be called directly from the UI 
* thread or the app will become unresponsive. 
*/ 
public class LocationHelper { 

    // 
    // Fields 
    // 

    /** 
    * The maximum accuracy, in metres, for the location fix to be considered accurate enough. 
    */ 
    private int accuracyRequired; 
    /** 
    * The maximum age, in seconds, for the location fix to be considered recent enough. 
    */ 
    private int ageRequired; 
    /** 
    * The Location obtained by the constructor 
    */ 
    private Location position; 
    /** 
    * An instance of the system location manager. 
    */ 
    private LocationManager lm; 
    /** 
    * The context passed in, in order to be able to access system resources like GPS. 
    */ 
    private Context mCtx; 
    /** 
    * The current time, set by the constructor. 
    */ 
    private long time; 
    /** 
    * A scaling factor which is applied to the accuracy of any network 
    * based location fix to compensate for the inaccuracy of its reporting. 
    */ 
    private static final float NETWORK_ACCURACY_SCALE = 5; 

    // 
    // Constructors 
    // 

    /** 
    * Constructor which will get a location fix (current or recent) which meets the 
    * criteria provided so that it can be acted on. 
    * @return 
    * @param  age The maximum age, in seconds, for the location fix to be 
    * considered recent enough. 
    * @param  accuracy The maximum accuracy, in metres, for the location fix to 
    * be considered accurate enough. 
    */ 
    public LocationHelper(Context ctx, int age, int accuracy) 
    { 
     mCtx = ctx; 
     setAgeRequired(age); 
     setAccuracyRequired(accuracy); 
     //Get the time (in milliseconds since UNIX epoch) 
     //TODO - need to test what happens when phone clock is wrong 
     Date now = new Date(); 
     time = now.getTime(); 
     //TODO - handle when LocationManager returns as null 
     lm = (LocationManager) mCtx.getSystemService(Context.LOCATION_SERVICE); 
     //Finally, get a fix to satisfy conditions (if a new fix is required then 
     //getCurrentFix() will detect this and call getCurrentFix() itself. 
     position = getRecentFix(); 
    } 

    // 
    // Methods 
    // 


    // 
    // Accessor methods 
    // 

    /** 
    * Set the value of accuracyRequired 
    * The maximum accuracy, in metres, for the location fix to be considered accurate 
    * enough. 
    * @param newVar the new value of accuracyRequired 
    */ 
    private void setAccuracyRequired (int acc) { 
     //TODO - Test that value is not negative 
     accuracyRequired = acc; 
    } 

    private void setAgeRequired (int age) { 
     //TODO - Test that the value is not negative 
     ageRequired = age; 
    } 


    // 
    // Other methods 
    // 



    /** 
    * Returns the location fix obtained by the constructor. 
    * @return  Location 
    */ 
    public Location getLocation() 
    { 
     return position; 
    } 


    /** 
    * Returns the distance between the user's location and a location provided as an 
    * argument. 
    * @return  float 
    * @param  location 
    */ 
    public float getDistance(Location location) 
    { 
     return position.distanceTo(location); 
    } 


    /** 
    * Obtains the most recent fixes from the GPS and Network location managers, and 
    * stores the more accurate of the two if it is accurate/recent enough, otherwise 
    * it will call getCurrentFix in order to get an accurate enough fix. 
    * @return  Location 
    */ 
    private Location getRecentFix() 
    { 
     //TODO - need to check if location sources are enabled, and deal with it if they aren't 

     Location GPSFix = lm.getLastKnownLocation("GPS"); 
     Location networkFix = lm.getLastKnownLocation("network"); 
     //Adjust the stated accuracy of the network location fix due to errors in reporting 
     networkFix.setAccuracy(networkFix.getAccuracy()/NETWORK_ACCURACY_SCALE); 

     if((GPSFix.getAccuracy() < accuracyRequired) & (time - GPSFix.getTime() < ageRequired)) 
     { 
      //Last GPS fix is good enough, so return it. 
      return GPSFix; 
     } 
     else if ((networkFix.getAccuracy() < accuracyRequired) & (time - networkFix.getTime() < ageRequired)) 
     { 
      //Last network fix is good enough, so return it. 
      return networkFix; 
     } 
     else { 
      //none of the available fixes are good enough, so obtain a new one. 
      return getCurrentFix(); 
     } 
    } 


    /** 
    * Obtains either a GPS or Network based LocationManager, and gets a new fix, if 
    * possible. GPS/Network is decided upon based accuracy required. 
    * @return  Location 
    */ 
    private Location getCurrentFix() 
    { 
     //TODO - need to put in some sort of timeout (perhaps getting status updates will do) 

     LocationListener networkListener = new LocationListener() { 
      public void onLocationChanged(Location loc) { 
       //check to see if new position is accurate enough 
       if (loc.getAccuracy() < accuracyRequired) { 
        position = loc; 
       } 
       else if (new Date().getTime() - time > 15000) { //if it has been looking for network location updates for 15 seconds or more 
        //Get updates from GPS instead 
        lm.requestLocationUpdates("gps", 0, 0, GPSListener); 
       } 
      } 
      public void onProviderDisabled(String provider) { 
       // TODO - network location is/has been disabled by user - do something like warn user it is a bad idea 

      } 
      public void onProviderEnabled(String provider) { 
      } 
      public void onStatusChanged(String provider, int status, Bundle extras) { 
       // TODO Auto-generated method stub 

      } 
     }; 

     LocationListener GPSListener = new LocationListener() { 
      public void onLocationChanged(Location loc) { 
       // TODO - check to see if new position is accurate enough 
       if (loc.getAccuracy() < accuracyRequired) { 
        position = loc; 
       } 
       else if (new Date().getTime() - time > 60000) { //if it has been looking for GPS location updates for 60 seconds or more 
        //TODO Report an error getting location 
       } 
      } 
      public void onProviderDisabled(String provider) { 
       // TODO - GPS is/has been turned off by user - do something like warn user it is a bad idea 

      } 
      public void onProviderEnabled(String provider) { 
      } 
      public void onStatusChanged(String provider, int status, Bundle extras) { 
       // TODO Auto-generated method stub 

      } 
     }; 



     if(accuracyRequired < 200) { 
      //First try network updates, then use GPS if sufficient accuracy not obtained in time 
      lm.requestLocationUpdates("network", 0, 0, networkListener); 
     } 
     else { 
      //GPS updates required for accuracy 
      lm.requestLocationUpdates("gps", 0, 0, GPSListener); 
     } 

     while (position == null){ 
      //Do nothing, this is just to stop the method returning the position until it has been set 
      try { 
       wait(50); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     return position; 
    } 


} 

回答

0

监听回调主线程上进行,所以你不能阻止主线程的位置(否则你的听众回调将永远不会happpen)。如果你的服务和你的活动在同一个进程中运行,那么这也是UI线程。为了使这项工作,你需要确保你的LocationHelper运行在一个单独的线程。然后,您可以添加一个while循环,该循环在检查新位置之间稍微休息一下。正如我前面所说,由于位置侦听器回调发生在主线程上,所以不会有阻塞。

当你说这是在后台服务中运行时,你可以更具体吗?那是什么意思?

+0

我的意思是它是一种服务,它运行在与主UI不同的线程中,并且没有任何用户交互。我认为你的答案解决了我的问题。谢谢。 – ablack89 2012-07-27 13:14:33

+0

很酷。我只是想确定你明白,即使一个Service有调用在主线程上执行的调用,并且如果你的服务与你的激活(这是默认行为)在同一个进程中,你可以阻止它们。 – 2012-07-27 14:09:33