2017-03-08 40 views
0

因此,我有自定義位置服務類,從中我想要獲取最後一個已知的位置。有可能,我可以在GoogleApiClient連接之前調用getLastKnownLocation(),所以我必須等待它,然後調用getLastKnownLocation(),但我不知道如何管理它。我認爲RxJava 2可以幫助我,但我並不熟悉這個框架。這是我的課現在:等待onConnected調用,獲取位置

import android.Manifest; 
import android.app.Activity; 
import android.content.pm.PackageManager; 
import android.os.Bundle; 
import android.support.annotation.NonNull; 
import android.support.annotation.Nullable; 
import android.support.v4.app.ActivityCompat; 
import android.util.Log; 

import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.api.GoogleApiClient; 
import com.google.android.gms.location.LocationListener; 
import com.google.android.gms.location.LocationRequest; 
import com.google.android.gms.location.LocationServices; 
import com.google.android.gms.maps.model.LatLng; 

import javax.inject.Inject; 

import pl.pancor.android.air.base.FragmentScope; 

@FragmentScope 
public class LocationService implements Location.Service, 
     GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, 
     ActivityCompat.OnRequestPermissionsResultCallback { 

    private static final String TAG = LocationService.class.getSimpleName(); 
    private static final int PERMISSIONS_REQUEST = 13; 

    private GoogleApiClient mGoogleApiClient; 

    private Activity mActivity; 

    private android.location.Location mLastLocation; 

    private Location.Receiver mReceiver; 

    @Inject 
    LocationService(Activity activity) { 

     mActivity = activity; 
    } 

    @Override 
    public void getLastKnownLocation() { 

     if (isPermissionsGranted(true)) 
      getLocation(); 

    } 

    /** 
    * @param request if permissions aren't granted and {@param request} is true, 
    *    then request permissions 
    * @return true if location permissions are granted 
    */ 
    private boolean isPermissionsGranted(boolean request) { 

     if (ActivityCompat.checkSelfPermission(mActivity, 
       Manifest.permission.ACCESS_FINE_LOCATION) != 
       PackageManager.PERMISSION_GRANTED && 
       ActivityCompat.checkSelfPermission(mActivity, 
         Manifest.permission.ACCESS_COARSE_LOCATION) != 
         PackageManager.PERMISSION_GRANTED) { 

      if (request) { 
       ActivityCompat.requestPermissions(mActivity, 
         new String[]{Manifest.permission.ACCESS_FINE_LOCATION, 
           Manifest.permission.ACCESS_COARSE_LOCATION}, 
         PERMISSIONS_REQUEST); 
      } 
      return false; 
     } 
     return true; 
    } 

    private void getLocation() { 

     if (mGoogleApiClient != null) 

      mLastLocation = LocationServices.FusedLocationApi 
       .getLastLocation(mGoogleApiClient); 

     if (mLastLocation != null) { 

      LatLng latLng = new LatLng(mLastLocation.getLatitude(), 
        mLastLocation.getLongitude()); 
      mReceiver.lastKnownLocation(latLng); 
     } else { 

      Log.e(TAG, "NULLLLLLLLLLLLLLLLLLLLLLL"); 
     } 
    } 

    @Override 
    public void onConnected(@Nullable Bundle bundle) { 

    } 

    @Override 
    public void onConnectionSuspended(int i) { 


    } 

    @Override 
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { 

    } 

    @Override 
    public void setupReceiver(Location.Receiver receiver) { 

     mReceiver = receiver; 
    } 

    @Override 
    public void onStart() { 

     if (mGoogleApiClient != null){ 

      mGoogleApiClient.connect(); 
     } else { 

      mGoogleApiClient = getGoogleApiClient(); 
      mGoogleApiClient.connect(); 
     } 
    } 

    @Override 
    public void onStop() { 

     if (mGoogleApiClient != null) 
      mGoogleApiClient.disconnect(); 
    } 

    private GoogleApiClient getGoogleApiClient(){ 

     return new GoogleApiClient.Builder(mActivity) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(LocationServices.API) 
       .build(); 
    } 

    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 
              @NonNull int[] grantResults) { 

     switch (requestCode){ 

      case PERMISSIONS_REQUEST: 

       if (grantResults.length > 0 && 
         grantResults[0] == PackageManager.PERMISSION_GRANTED){ 

        getLastKnownLocation(); 
       } else { 

       } 
     } 
    } 
} 

我需要以某種方式來檢查是否mGoogleApiClient連接(mGoogleApiClient.isConnected()),如果沒有,請等待連接,然後從FusedLocationApi得到的位置,但我不想要將方法放入onConnected(),因爲它有時會返回位置,當我不想返回位置時。

+0

你能在一個小更詳細的解釋你是什​​麼意思: 「但我不想把方法放在onConnected(),因爲它有時會返回位置,當我不想返回位置。」 – mjekov

+0

我的演示者調用mLocationService.getLastKnownLocation(),然後在LocationService中創建mGoogleApiClient並將其連接,並在onConnected()中放入mReceiver.lastKnownLocation(latLng),然後將位置發回給演示者。我更快地構建和連接mGoogleApiClient(onStart()在fragment中的onViewCreated()中調用),有時當我調用getLastKnownLocation()時,mGoogleApiClient尚未連接,所以我必須等待它。而現在,我不知道如何在沒有將mReceiver.lastKnownLocation(latLng)放入onConnected()的情況下等待它。 – Panczur

回答

1

所以,一段時間後,我設法使它也完成了我的整個類,我想與大家分享,我做了什麼

public interface Location { 

    interface Service extends BaseLocation<Receiver>{ 

     void onStart(); 

     void onStop(); 

     void onActivityResult(int requestCode, int resultCode); 

     void getLastKnownLocation(); 
    } 

    interface Receiver{ 

     void lastKnownLocation(double latitude, double longitude); 

     void userRefusedToSendLocation(); 

     void unableToObtainLocation(); 
    } 
} 



import android.Manifest; 
import android.app.Activity; 
import android.content.IntentSender; 
import android.content.pm.PackageManager; 
import android.os.Bundle; 
import android.os.Handler; 
import android.support.annotation.NonNull; 
import android.support.annotation.Nullable; 
import android.support.v4.app.ActivityCompat; 
import android.util.Log; 

import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.GoogleApiAvailability; 
import com.google.android.gms.common.api.GoogleApiClient; 
import com.google.android.gms.common.api.PendingResult; 
import com.google.android.gms.common.api.ResultCallback; 
import com.google.android.gms.common.api.Status; 
import com.google.android.gms.location.LocationListener; 
import com.google.android.gms.location.LocationRequest; 
import com.google.android.gms.location.LocationServices; 
import com.google.android.gms.location.LocationSettingsRequest; 
import com.google.android.gms.location.LocationSettingsResult; 
import com.google.android.gms.location.LocationSettingsStatusCodes; 

import javax.inject.Inject; 

import pl.pancor.android.air.base.FragmentScope; 

@FragmentScope 
public class LocationService implements Location.Service, 
     GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, 
     ActivityCompat.OnRequestPermissionsResultCallback, LocationListener, 
     ResultCallback<LocationSettingsResult>{ 

    private static final int PERMISSIONS_REQUEST = 13; 
    private static final int SETTINGS_CHECK = 23; 
    private static final int GOOGLE_API_CLIENT_ERROR = 33; 

    private static final int LOCATION_EXPIRATION_TIME = 10 * 1000; 
    private static final int LOCATION_INTERVAL = 2 * 1000; 

    private GoogleApiClient mGoogleApiClient; 

    private Activity mActivity; 

    private LocationRequest mLocationRequest; 
    private android.location.Location mLastLocation; 

    private Location.Receiver mReceiver; 

    private Handler mHandler; 
    private final Runnable mExpiredLocationUpdate = new Runnable() { 
     @Override 
     public void run() { 
      mReceiver.unableToObtainLocation(); 
     } 
    }; 

    private boolean isWaitingForConnect = false; 

    @Inject 
    LocationService(Activity activity) { 

     mActivity = activity; 
    } 

    @Override 
    public void getLastKnownLocation() { 

     if (isPermissionsGranted(true)) 
      checkLocationSettings(); 
    } 

    @Override 
    public void onActivityResult(int requestCode, int resultCode) { 

     resolveProblems(requestCode, resultCode); 
    } 

    @Override 
    public void onLocationChanged(android.location.Location location) { 

     if (mLastLocation == null) { 

      mLastLocation = location; 
      sendLatLngToReceiver(); 
     } 

     LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); 
     mHandler.removeCallbacks(mExpiredLocationUpdate); 
    } 

    @Override 
    public void onConnected(@Nullable Bundle bundle) { 

     if (isWaitingForConnect) 
      getLastKnownLocation(); 
    } 

    @Override 
    public void onConnectionSuspended(int i) { 

     //mGoogleApiClient will automatically try to reconnect 
    } 

    @Override 
    public void onConnectionFailed(@NonNull ConnectionResult result) { 

     if (!result.hasResolution()){ 
      mReceiver.unableToObtainLocation(); 
      GoogleApiAvailability.getInstance() 
        .getErrorDialog(mActivity, result.getErrorCode(), 0).show(); 
      return; 
     } 
     if (mActivity.hasWindowFocus()) { 
      try { 
       result.startResolutionForResult(mActivity, GOOGLE_API_CLIENT_ERROR); 
      } catch (IntentSender.SendIntentException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    @Override 
    public void setupReceiver(Location.Receiver receiver) { 

     mReceiver = receiver; 
    } 

    @Override 
    public void onStart() { 

     mHandler = new Handler(); 

     if (mGoogleApiClient != null){ 

      mGoogleApiClient.connect(); 
     } else { 

      mGoogleApiClient = getGoogleApiClient(); 
      mGoogleApiClient.connect(); 
     } 
    } 

    @Override 
    public void onStop() { 

     if (mGoogleApiClient != null) { 
      LocationServices.FusedLocationApi.removeLocationUpdates(
        mGoogleApiClient, this); 

      mGoogleApiClient.disconnect(); 
     } 
     mHandler.removeCallbacks(mExpiredLocationUpdate); 
    } 

    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 
              @NonNull int[] grantResults) { 

     switch (requestCode){ 
      case PERMISSIONS_REQUEST: 

       if (grantResults.length > 0 && 
         grantResults[0] == PackageManager.PERMISSION_GRANTED){ 

        getLastKnownLocation(); 
       } else { 

        mReceiver.userRefusedToSendLocation(); 
       } 
     } 
    } 

    @Override 
    public void onResult(@NonNull LocationSettingsResult result) { 

     final Status status = result.getStatus(); 
     switch (status.getStatusCode()){ 
      case LocationSettingsStatusCodes.SUCCESS: 

       getLocation(); 
       break; 
      case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: 

       if (mActivity.hasWindowFocus()) { 
        try { 
         status.startResolutionForResult(mActivity, SETTINGS_CHECK); 
        } catch (IntentSender.SendIntentException e) { 
         e.printStackTrace(); 
        } 
       } 
       break; 
      case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: 

       mReceiver.unableToObtainLocation(); 
       break; 
     } 
    } 

    private void checkLocationSettings() { 

     if (mGoogleApiClient != null){ 

      mLocationRequest = new LocationRequest() 
        .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) 
        .setFastestInterval(LOCATION_INTERVAL/2) 
        .setInterval(LOCATION_INTERVAL) 
        .setNumUpdates(1); 

      LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder() 
        .addLocationRequest(mLocationRequest); 

      PendingResult<LocationSettingsResult> result = LocationServices 
        .SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build()); 
      result.setResultCallback(this); 
     } 
    } 

    private void getLocation(){ 

     if (mGoogleApiClient != null) 
      mLastLocation = LocationServices.FusedLocationApi 
        .getLastLocation(mGoogleApiClient); 

     sendLatLngToReceiver(); 
    } 

    private void sendLatLngToReceiver(){ 

     if (mLastLocation != null) { 

      mReceiver.lastKnownLocation(mLastLocation.getLatitude(), 
        mLastLocation.getLongitude()); 
      mHandler.removeCallbacks(mExpiredLocationUpdate); 
     } else { 

      requestLocation(); 
     } 
    } 

    private void requestLocation(){ 

     if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { 

      LocationServices.FusedLocationApi.requestLocationUpdates(
        mGoogleApiClient, mLocationRequest, this); 
      mHandler.postDelayed(mExpiredLocationUpdate, LOCATION_EXPIRATION_TIME); 
     } else { 

      isWaitingForConnect = true; 
     } 
    } 

    /** 
    * @param request if permissions aren't granted and {@param request} is true, 
    *    then request permissions 
    * @return true if location permissions are granted 
    */ 
    private boolean isPermissionsGranted(boolean request) { 

     if (ActivityCompat.checkSelfPermission(mActivity, 
       Manifest.permission.ACCESS_FINE_LOCATION) != 
       PackageManager.PERMISSION_GRANTED && 
       ActivityCompat.checkSelfPermission(mActivity, 
         Manifest.permission.ACCESS_COARSE_LOCATION) != 
         PackageManager.PERMISSION_GRANTED) { 

      if (request) { 
       ActivityCompat.requestPermissions(mActivity, 
         new String[]{Manifest.permission.ACCESS_FINE_LOCATION, 
           Manifest.permission.ACCESS_COARSE_LOCATION}, 
         PERMISSIONS_REQUEST); 
      } 
      return false; 
     } 
     return true; 
    } 

    private GoogleApiClient getGoogleApiClient(){ 

     return new GoogleApiClient.Builder(mActivity) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(LocationServices.API) 
       .build(); 
    } 

    private void resolveProblems(int requestCode, int resultCode){ 

     switch (requestCode){ 
      case SETTINGS_CHECK: 
       switch (resultCode){ 
        case Activity.RESULT_OK: 
         getLastKnownLocation(); 
         break; 
        case Activity.RESULT_CANCELED: 
         mReceiver.userRefusedToSendLocation(); 
         break; 
       } 
       break; 
      case GOOGLE_API_CLIENT_ERROR: 
       switch (resultCode) { 
        case Activity.RESULT_OK: 
         mGoogleApiClient.connect(); 
         break; 
        case Activity.RESULT_CANCELED: 
         mReceiver.unableToObtainLocation(); 
         break; 
       } 
     } 
    } 
} 
1

在評論部分的解釋之後,我會做這樣的事情:

  1. 在接收器/片段類

    我把那臺變量「updateUI」爲真在LocationService類中的一些邏輯,適合onConnected調用mReceiver.lastKnownLocation(latLng) 方法。默認值爲false,如果在接收器準備好之前調用onConnected,則不會調用方法mReceiver.lastKnownLocation(latLng)

  2. 另一種方法是始終將最後一個已知位置存儲在SharedPreferences中(或至少在方法中)。然後,您可以在第一次需要位置時使用它,稍後再等待更精確的位置,但在開始時此方法不會如此精確。