我正在尝试使用非阻塞的FusedLocationProvider API作为阻塞API。这是我正在做的事情(大致):
countDownLatch.await(timeOut,timeUnit)
countDownLatch.countdown()
,这将释放锁定。我需要一种方法来阻止,因为我可能需要在任何时间点计算位置并使用它。上面的方法是有效的,但我正在寻找一种更好的方法,因为CountDownLatch是从它阻塞的同一个线程触发的。我不知道这样做是不是在犯亵渎/亵渎神灵。
这是我的代码:
public class BlockingLocationProvider implements ConnectionCallbacks,
OnConnectionFailedListener, LocationListener {
private static final String TAG = "BlockingLocationProvider";
private LocationInfo mLocInfoRow;
private long mCallTime;
private Double mDel;
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationRequest locationRequest;
private boolean mLocationCalculated = false;
private CountDownLatch latch;
private Context context;
private ConnectionResult gApiConnResult;
@Override
public void onConnectionFailed(ConnectionResult arg0) {
Logger.error(TAG, "Google play services error while getting location.");
mLocInfoRow = new LocationInfo().timestamp(System.currentTimeMillis())
.status(LocStatus.ERR_G_PLAY).statusCode(arg0.getErrorCode());
mLocation = null;
mLocationCalculated = true;
latch.countDown();
}
@Override
public void onConnected(Bundle arg0) {
locationRequest = new LocationRequest();
locationRequest.setInterval(0).setNumUpdates(1)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setExpirationDuration(2000);
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, locationRequest, this);
}
@Override
public void onConnectionSuspended(int arg0) {
Logger.warning(TAG, "Can't handle suspension.");
mLocInfoRow = new LocationInfo().timestamp(System.currentTimeMillis())
.status(LocStatus.ERR_UNKNOWN).statusCode(-200);
latch.countDown();
}
@Override
public void onLocationChanged(Location arg0) {
mLocation = arg0;
if (mLocation == null) {
Logger.debug(TAG, "Fused provider returned null");
mLocInfoRow = new LocationInfo()
.timestamp(System.currentTimeMillis())
.status(LocStatus.ERR_FUSED_NULL).statusCode(-3);
} else {
Logger.debug(TAG, "Got a location from fused provider.");
mLocInfoRow = new LocationInfo().timestamp(mLocation.getTime())
.lat(mLocation.getLatitude()).lng(mLocation.getLongitude())
.travelSpeed(mLocation.getSpeed())
.altitude(mLocation.getAltitude())
.acc(mLocation.getAccuracy()).provider("fused")
.status("OK").statusCode(0);
}
mLocationCalculated = true;
latch.countDown();
}
public LocationInfo getLocationInfo(Context ctx) {
this.context = ctx;
calcLocation();
return mLocInfoRow;
}
public Location getLocation(Context ctx) {
this.context = ctx;
calcLocation();
return mLocation;
}
// This should block
public void calcLocation() {
if (Thread.currentThread().getName().equals("main")) {
throw new RuntimeException("Cannot run " + TAG + " on UI thread.");
}
latch = new CountDownLatch(1);
/* To figure how long it takes to calc location */
mCallTime = System.currentTimeMillis();
Logger.verbose(TAG, "Checking play services.");
// First check play services
int playServicesAvailable = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(context);
// whoopsie!
if (playServicesAvailable != ConnectionResult.SUCCESS) {
Logger.error(TAG,
"Google play services error while getting location.");
mLocInfoRow = new LocationInfo()
.timestamp(System.currentTimeMillis())
.status(LocStatus.ERR_G_PLAY)
.statusCode(playServicesAvailable);
mLocation = null;
return;
}
Logger.verbose(TAG, "Checking GPS.");
// Then check GPS enabled or not
if (!isGpsEnabled(context)) {
Logger.error(TAG,
"User has disabled GPS. Unable to provide location updates.");
mLocInfoRow = new LocationInfo()
.timestamp(System.currentTimeMillis())
.status(LocStatus.ERR_NO_GPS).statusCode(-2);
mLocation = null;
return;
}
Logger.verbose(TAG, "Connecting to play services.");
// Then connect to play services client
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
if (!(mGoogleApiClient.isConnected() || mGoogleApiClient.isConnecting())) {
gApiConnResult = mGoogleApiClient.blockingConnect(5,
TimeUnit.SECONDS);
}
boolean timeout = false;
if (gApiConnResult.isSuccess()) {
try {
Logger.warning(TAG, "Waiting latch on location request...");
timeout = !latch.await(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (timeout) {
Logger.warning(TAG, "Latch timeout!");
mLocInfoRow = new LocationInfo()
.timestamp(System.currentTimeMillis())
.status(LocStatus.ERR_TIMEOUT).statusCode(-100);
} else {
Logger.debug(TAG, "Latch triggered!");
}
} else {
Logger.warning(TAG, "gApi connect timeout!");
mLocInfoRow = new LocationInfo()
.timestamp(System.currentTimeMillis())
.status(LocStatus.ERR_TIMEOUT).statusCode(-300);
}
mDel = (Double.valueOf(System.currentTimeMillis() - mCallTime) / 1000);
Logger.debug(TAG, "Took " + mDel + " seconds for location update.");
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
private static boolean isGpsEnabled(final Context ctx) {
LocationManager lm = (LocationManager) ctx
.getSystemService(Context.LOCATION_SERVICE);
return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
}
除了无限循环上的锁存器之外,还有其他策略吗?在这种情况下要阻止的标志?感谢。