将非阻塞的android FusedProvider API转换为阻止

时间:2015-03-13 07:03:16

标签: android multithreading countdownlatch fusedlocationproviderapi

我正在尝试使用非阻塞的FusedLocationProvider API作为阻塞API。这是我正在做的事情(大致):

  1. 启动AsyncTask
  2. 在后台线程中,连接到 PlayServices / FusedProvider API。有一种阻止方法,可以使用超时。
  3. 使用上述API请求位置更新。 API将使用设备计算位置并触发在调用者线程上执行的回调。
  4. 使用countDownLatch.await(timeOut,timeUnit)
  5. 等待回调
  6. 当Fused API触发回调时,检索位置并执行countDownLatch.countdown(),这将释放锁定。
  7. 返回位置。
  8. 我需要一种方法来阻止,因为我可能需要在任何时间点计算位置并使用它。上面的方法是有效的,但我正在寻找一种更好的方法,因为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);
        }
    
    }
    

    除了无限循环上的锁存器之外,还有其他策略吗?在这种情况下要阻止的标志?感谢。

0 个答案:

没有答案