我有一个类LocationHelper,我正在设计它以获取用户位置。在创建时,我指定所需的准确度,以及该位置的当前时间。如果它必须是新获得的位置,或者之前没有足够的位置,那么我想开始从位置管理器监听更新。我的问题是我希望在其中一个方法中发生这种情况,并且方法在找到足够准确的位置之前不要返回。在获得我想要的位置之前,如何停止返回方法?我只在后台服务中使用LocationHelper类,所以我不关心它需要很长时间才能返回。 我想过在返回之前放一个while循环来检查position是否为null(直到找到一个足够准确的位置),如果是,那么它会执行一个等待,但我是否认为这会阻止侦听器接收更新?
如果我的解释不够清楚(我的问题在于底部的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 :(得分:0)
位置侦听器回调是在主线程上进行的,因此您无法阻止主线程(否则您的侦听器回调将永远不会开心)。如果您的服务在与您的活动相同的过程中运行,那么这也是UI线程。为了完成这项工作,您需要确保LocationHelper
在单独的线程中运行。然后,您可以添加一个while
循环,在检查新位置之间稍微休息一下。正如我之前所说,由于位置监听器回调发生在主线程上,因此不会阻塞。
当您说这是在后台服务中运行时,您能否更加具体。你的意思是什么?