2017-02-17 16 views
0

Ищет помощь в работе с моим приложением относительно получения текущего местоположения устройства. Ниже приведен класс GPSLocationListener, который я использую.FusedLocationApi метод getLastLocation() всегда null во время первого вызова

import android.Manifest; 
import android.app.Activity; 
import android.content.pm.PackageManager; 
import android.location.Location; 
import android.os.Build; 
import android.os.Bundle; 
import android.support.annotation.NonNull; 
import android.support.v4.app.ActivityCompat; 
import android.support.v4.content.ContextCompat; 
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; 



/** 
* This class takes care of capturing the location of the device. 
*/ 
public class GPSLocationListener implements GoogleApiClient.ConnectionCallbacks, 
     GoogleApiClient.OnConnectionFailedListener, LocationListener, 
     ActivityCompat.OnRequestPermissionsResultCallback { 


    protected static final String TAG = "location-updates-sample"; 

    public static final int LOCATION_RESQUEST = 1; 
    /** 
    * The desired interval for location updates. Inexact. Updates may be more or less frequent. 
    */ 
    public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000; 

    /** 
    * The fastest rate for active location updates. Exact. Updates will never be more frequent 
    * than this value. 
    */ 
    public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 
      UPDATE_INTERVAL_IN_MILLISECONDS/2; 

    /** 
    * Provides the entry point to Google Play services. 
    */ 
    protected GoogleApiClient mGoogleApiClient; 

    /** 
    * Stores parameters for requests to the FusedLocationProviderApi. 
    */ 
    protected LocationRequest mLocationRequest; 

    /** 
    * Represents a geographical location. 
    */ 
    protected Location mCurrentLocation; 

    private Activity mActivity; 

    public double lat; 
    public double lon; 

    public GPSLocationListener(Activity activity) { 
     this.mActivity = activity; 
     // Kick off the process of building a GoogleApiClient and requesting the LocationServices API. 
     buildGoogleApiClient(); 
    } 

    /** 
    * Builds a GoogleApiClient. Uses the {@code #addApi} method to request the 
    * LocationServices API. 
    */ 
    protected synchronized void buildGoogleApiClient() { 
     Log.i(TAG, "Building GoogleApiClient"); 
     mGoogleApiClient = new GoogleApiClient.Builder(mActivity) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(LocationServices.API) 
       .build(); 
     createLocationRequest(); 
    } 

    /** 
    * Sets up the location request. Android has two location request settings: 
    * {@code ACCESS_COARSE_LOCATION} and {@code ACCESS_FINE_LOCATION}. These settings control 
    * the accuracy of the current location. This sample uses ACCESS_FINE_LOCATION, as defined in 
    * the AndroidManifest.xml. 
    * <p/> 
    * When the ACCESS_FINE_LOCATION setting is specified, combined with a fast update 
    * interval (5 seconds), the Fused Navigation Provider API returns location updates that are 
    * accurate to within a few feet. 
    * <p/> 
    * These settings are appropriate for mapping applications that show real-time location 
    * updates. 
    */ 
    protected void createLocationRequest() { 
     mLocationRequest = new LocationRequest(); 

     // Sets the desired interval for active location updates. This interval is 
     // inexact. You may not receive updates at all if no location sources are available, or 
     // you may receive them slower than requested. You may also receive updates faster than 
     // requested if other applications are requesting location at a faster interval. 
     mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); 

     // Sets the fastest rate for active location updates. This interval is exact, and your 
     // application will never receive updates faster than this value. 
     mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); 

     mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 
    } 

    /** 
    * Requests location updates from the FusedLocationApi. 
    */ 
    public void startLocationUpdates(){ 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      if (ContextCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { 
       //return; 
      }else { 
       try { 
        ActivityCompat.requestPermissions(this.mActivity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, 
            Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.INTERNET}, 
          LOCATION_RESQUEST); 
       }catch (Exception e){ 
        e.printStackTrace(); 
       } 
      } 
      // If the initial location was never previously requested, we use 
      // FusedLocationApi.getLastLocation() to get it. If it was previously requested, we store 
      // its value in the Bundle and check for it in onCreate(). 
      LocationServices.FusedLocationApi.requestLocationUpdates(
        mGoogleApiClient, mLocationRequest, this); 
     } 
    } 

    /** 
    * Removes location updates from the FusedLocationApi. 
    */ 
    protected void stopLocationUpdates() { 
     // It is a good practice to remove location requests when the activity is in a paused or 
     // stopped state. Doing so helps battery performance and is especially 
     // recommended in applications that request frequent location updates. 

     // The final argument to {@code requestLocationUpdates()} is a LocationListener 
     // (http://developer.android.com/reference/com/google/android/gms/location/LocationListener.html). 
     LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); 
    } 

    public void onStart() { 
     mGoogleApiClient.connect(); 
     //createLocationRequest(); 
     // Within {@code onPause()}, we pause location updates, but leave the 
     // connection to GoogleApiClient intact. Here, we resume receiving 
     // location updates if the user has requested them. 

    } 

    public void onStop() { 
     // Stop location updates to save battery, but don't disconnect the GoogleApiClient object. 
     if (mGoogleApiClient.isConnected()) { 
      stopLocationUpdates(); 
      mGoogleApiClient.disconnect(); 
     } 

    } 

    /** 
    * Runs when a GoogleApiClient object successfully connects. 
    */ 
    @Override 
    public void onConnected(Bundle connectionHint) { 
     Log.i(TAG, "Connected to GoogleApiClient"); 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      if (ContextCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.mActivity, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { 
       Log.i(TAG, "onConnected: Just empty if statement"); 
      }else { 
       try { 
        ActivityCompat.requestPermissions(this.mActivity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, 
            Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.INTERNET}, 
          LOCATION_RESQUEST); 
       }catch (Exception e){ 
        e.printStackTrace(); 
       } 
      } 
      mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); 
      if (mCurrentLocation == null) { 
       mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); 
       Log.i(TAG, "onConnected " + String.valueOf(mCurrentLocation)); 
      } 
     } 
    } 

    /** 
    * Callback that fires when the location changes. 
    */ 
    @Override 
    public void onLocationChanged(Location location) { 
     mCurrentLocation = location; 
     Log.i(TAG, "onLocationChanged: " + String.valueOf(mCurrentLocation.getLatitude())); 
     Log.i(TAG, "onLocationChanged: " + String.valueOf(mCurrentLocation.getLongitude())); 
    } 

    @Override 
    public void onConnectionSuspended(int cause) { 
     // The connection to Google Play services was lost for some reason. We call connect() to 
     // attempt to re-establish the connection. 
     Log.i(TAG, "Connection suspended"); 
     mGoogleApiClient.connect(); 
    } 

    @Override 
    public void onConnectionFailed(ConnectionResult result) { 
     // Refer to the javadoc for ConnectionResult to see what error codes might be returned in 
     // onConnectionFailed. 
     Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode()); 
    } 

    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      mActivity.onRequestPermissionsResult(requestCode, permissions, grantResults); 
     } 
     switch (requestCode){ 
      case LOCATION_RESQUEST: 
       if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ 
        startLocationUpdates(); // Calling this here is the only place that does not make the app crash 
        getCurrentLocation(); 
       }else { 
        Log.i(TAG, "onRequestPermissionsResult: Need Permissions"); 
        return; 
       } 
       break; 
      default: 
       break; 
     } 
     return; 
    } 

    public void getCurrentLocation(){ 
     if (mCurrentLocation != null){ 
      lat = mCurrentLocation.getLatitude(); 
      lon = mCurrentLocation.getLongitude(); 
      Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLatitude())); 
      Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLongitude())); 
     } 
    } 

    public GoogleApiClient getGoogleApiClient(){ 
     return mGoogleApiClient; 
    } 

} 

Пробуя это на своем фактическом устройстве с включенным GPS в настройках, я получаю странное поведение. Если я вообще этого не делаю, вызовите метод startLocationUpdates() или я вызываю его в методе onRequestPermissionsResult(), приложение запускается нормально, и когда я предоставляю разрешения на размещение устройств, объект mCurrentLocation имеет значение NULL, но не сбой. Я останавливаю приложение и снова запускаю его, а mCurrentLocation имеет координаты широты и долготы, которые я могу видеть в логарифме, чего я хочу в первую очередь, но они сохраняют только значения после второго запуска. Теперь, если я удалить приложение и попытаться вызвать метод startLocationUpdates() в любом месте, то приложение падает при запуске с ошибкой:

Client must have ACCESS_FINE_LOCATION permission to request PRIORITY_HIGH_ACCURACY locations. 

Но я проверка прав доступа в методе onConnected(), а также в методе startLocationUpdates(), а также, хотя я не думаю, что это правильно, но это единственный способ, которым я могу получить Android студии не подчеркнуть заявление

LocationServices.FusedLocationApi.requestLocationUpdates(
        mGoogleApiClient, mLocationRequest, this); 

в красном с предупреждением Permissions.

Вот Activity, где я пытаюсь получить обновления местоположения с помощью метода mapItBtnRespond().

package com.example.bigdaddy.as_built_weldmapper; 

import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.ArrayAdapter; 
import android.widget.EditText; 
import android.widget.Spinner; 
import android.widget.Toast; 

import com.example.bigdaddy.as_built_weldmapper.utilities.BendHelper; 
import com.example.bigdaddy.as_built_weldmapper.utilities.GPSLocationListener; 

public class SagActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener, 
     MajorButtonFragment.OnFragmentInteractionListener, Communicator{ 

    /* Using this to insert into the Bend Direction field. */ 
    public static String SAG_DIRECTION = "SAG"; 

    /* This spinner holds the bend types */ 
    Spinner mSagBendTypesSpinner; 

    /* Using this string to collect what was selected for the spinner type */ 
    private String mBendTypeSpinnerVal; 

    /* All the EditText for the Activity */ 
    private EditText mSagGpsShotEt; 
    private EditText mSagExistingGpsEt; 
    private EditText mSagCoverEt; 
    private EditText mSagDegreeEt; 
    private EditText mSagDistanceFromEt; 
    private EditText mSagNotesEt; 
    private EditText mSagOccupyIdEt; 
    private EditText mSagStationNumEt; 

    private GPSLocationListener mGPSLocationListener; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_sag); 

     mGPSLocationListener = new GPSLocationListener(SagActivity.this); 

     /* checking if the MajorButtonFragment is null */ 
     if (findViewById(R.id.majorButtonFragment) != null) { 
      if (savedInstanceState != null) { 
       return; 
      } 
     } 

     /* Referencing the spinner and setting the itemsSelectedListener */ 
     mSagBendTypesSpinner = (Spinner) findViewById(R.id.bend_types_spinner); 
     mSagBendTypesSpinner.setOnItemSelectedListener((AdapterView.OnItemSelectedListener) this); 
     /* Create an ArrayAdapter using the string array and a default spinner layout */ 
     ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, 
       R.array.bend_types_array, android.R.layout.simple_spinner_item); 
     /* Specify the layout to use when the list of choices appears */ 
     adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
     /* Apply the adapter to the spinner */ 
     mSagBendTypesSpinner.setAdapter(adapter); 

     /* Referencing and calling all the EditText for the Activity */ 
     mSagGpsShotEt = (EditText) findViewById(R.id.eTextGpsShotForSag); 
     mSagExistingGpsEt = (EditText) findViewById(R.id.eTextExistGradeForSag); 
     mSagCoverEt = (EditText) findViewById(R.id.eTextCoverForSag); 
     mSagDegreeEt = (EditText) findViewById(R.id.eTextDegreeForSag); 
     mSagDistanceFromEt = (EditText) findViewById(R.id.eTextDistanceFromForSag); 
     mSagNotesEt = (EditText) findViewById(R.id.eTextNotesForSagActivity); 
     mSagOccupyIdEt = (EditText) findViewById(R.id.eTextJointIdSagActivity); 
     mSagStationNumEt = (EditText) findViewById(R.id.eTextStationNumSagActivity); 
    } /*onCreate() ends here.*/ 

    @Override 
    protected void onStart() { 
     super.onStart(); 
     Log.i("SagActivity", "onStart: "); 
     /* Starting the location listener here (GoogleApiClient) */ 
     if (mGPSLocationListener != null){ 
      mGPSLocationListener.onStart(); 
     } 
    } 

    @Override 
    protected void onStop() { 
     super.onStop(); 
     Log.i("SagActivity", "onStop: "); 
     /* Stopping the location listener here (GoogleApiClient) */ 
     if (mGPSLocationListener != null){ 
      mGPSLocationListener.onStop(); 
     } 
    } 

    @Override 
    public void onLocalVoiceInteractionStopped() { 
     super.onLocalVoiceInteractionStopped(); 
    } 

    @Override 
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
     mBendTypeSpinnerVal = mSagBendTypesSpinner.getSelectedItem().toString(); 
    } 

    @Override 
    public void onNothingSelected(AdapterView<?> adapterView) { 

    } 

    @Override 
    public void exitBtnRespond() { 

    } 

    /** 
    * This overridden method comes from the Communicator Interface and is used globally in all 
    * Activities that implement it to Store (write) a transaction to the database. 
    * The utility class saveAndInsertBend() method is invoked here. 
    */ 
    @Override 
    public void storeBtnRespond() { 
     BendHelper.saveAndInsertBend(SagActivity.this, SAG_DIRECTION, mBendTypeSpinnerVal, mSagStationNumEt, 
       mSagOccupyIdEt, mSagDegreeEt, mSagDistanceFromEt, mSagGpsShotEt, mSagExistingGpsEt, 
       mSagCoverEt, mSagNotesEt); 
    } 

    @Override 
    public void mapItBtnRespond() { 
     Toast.makeText(this, "MapItBtn clicked in SagActivity",Toast.LENGTH_LONG).show(); 
     mGPSLocationListener.getCurrentLocation(); 
     Log.i("SagActivity", "mapItBtnRespond: " + String.valueOf(mGPSLocationListener.lat)); 
     Log.i("SagActivity", "mapItBtnRespond: " + String.valueOf(mGPSLocationListener.lon)); 
    } 

    @Override 
    public void onFragmentInteraction() { 

    } 

} 

Что я здесь делаю неправильно со всем этим? Любая помощь будет принята с благодарностью, поскольку я смущен с разрешениями. Большое спасибо за любое руководство.

+0

Почему вы не спросить разрешения, когда метод getCurrentLocation() вызывается в SagActivity ? – tahsinRupam

+0

@tahsinRupam. Я тоже подумал об этом, но я планирую использовать класс помощника GPS в нескольких действиях и надеяться позаботиться о запросе разрешений раз и навсегда в пределах этого класса, а не для каждого действия отдельно. – J2112O

ответ

1

Вы запрашиваете разрешение FINE_LOCATION в onConnected(), но onConnected вызывается при подключении GPS. Именно по этой причине вы получаете ошибку разрешения.

Вы должны удалить это:

mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); 

От onConnected(). Добавьте к этому getCurrentLocation() с запросом разрешения:

public void getCurrentLocation(){ 
     //Request permission here 
     mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); 
     if (mCurrentLocation != null){ 
      lat = mCurrentLocation.getLatitude(); 
      lon = mCurrentLocation.getLongitude(); 
      Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLatitude())); 
      Log.i(TAG, "getCurrentLocation(): " + String.valueOf(mCurrentLocation.getLongitude())); 
     } 
    } 

Затем также называют этот метод в onConnected():

@Override 
    public void onConnected(Bundle connectionHint) { 
     Log.i(TAG, "Connected to GoogleApiClient"); 
      getCurrentLocation(); 
    } 
+0

Работает идеально. Огромное спасибо. Принимается маркировка. Я ценю вашу помощь. – J2112O

+0

в любое время :) рад, что это помогло. – tahsinRupam