我有一个类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;
}
}
我的意思是它是一种服务,它运行在与主UI不同的线程中,并且没有任何用户交互。我认为你的答案解决了我的问题。谢谢。 – ablack89 2012-07-27 13:14:33
很酷。我只是想确定你明白,即使一个Service有调用在主线程上执行的调用,并且如果你的服务与你的激活(这是默认行为)在同一个进程中,你可以阻止它们。 – 2012-07-27 14:09:33