How to get user's current location in Android

2019-05-21 06:01发布

问题:

I want to fetch user's current lat long on click of a button. I know that you can get the last known location using FusedLocationApi. But what I am not able to understand is, gps or location services needs to be turned on for this? If yes, how to check that the user has turned on location and get the current location. Also, how to include marshmallow permission checks in getting the location.

I have already referred: 1) googlesamples/android-play-location 2) googlesamples/android-XYZTouristAttractions and many other links but unable to make a complete flow.

Code

public class AccessLocationFragment extends BaseFragment implements View.OnClickListener, LocationListener,
    GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, GeneralDialogFragment.GeneralDialogClickListener {

private static final int MY_PERMISSIONS_REQUEST_LOCATION = 101;
private static final String TAG = AccessLocationFragment.class.getSimpleName();
private static final int REQUEST_CHECK_SETTINGS = 102;
private Button mAccessLocation;
private EditText mZipCode;
private Dialog progressDialog;
private GoogleApiClient mGoogleApiClient;
private Location mLastLocation;

public static AccessLocationFragment newInstance() {
    return new AccessLocationFragment();
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_access_location, container, false);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    RecycleApplication.getEventBus().register(this);
    mAccessLocation = (Button) view.findViewById(R.id.access_location);
    mZipCode = (EditText) view.findViewById(R.id.zip_code);
    mAccessLocation.setOnClickListener(this);

    mZipCode.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (actionId == EditorInfo.IME_ACTION_DONE) {
                String zipCode = mZipCode.getText().toString().trim();
                if (TextUtils.isEmpty(zipCode)) {
                    Toast.makeText(mActivity, "Please enter zip code", Toast.LENGTH_SHORT).show();
                } else {
                    Call<Address> response = mRecycleService.getAddress(zipCode);
                    response.enqueue(new GetLocationCallback(AccessLocationFragment.this));
                }
            }
            return false;
        }
    });
    // Create an instance of GoogleAPIClient.
    if (mGoogleApiClient == null) {
        mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }
    if (!LocationUtils.checkFineLocationPermission(mActivity)) {
        // See if user has denied permission in the past
        if (shouldShowRequestPermissionRationale(android.Manifest.permission.ACCESS_FINE_LOCATION)) {
            // Show a simple snackbar explaining the request instead
            showPermissionSnackbar();
        } else {
            requestFineLocationPermission();
        }
    } else {
        displayLocationSettingsRequest();
    }
}

private void startHomeActivity(Address address) {
    RecyclePreferences.getInstance().setCity(address.getCity());
    RecyclePreferences.getInstance().setState(address.getState());
    RecyclePreferences.getInstance().setLatitude(address.getLatitude());
    RecyclePreferences.getInstance().setLongitude(address.getLongitude());
    RecyclePreferences.getInstance().setZipCode(address.getZipCode());
    startActivity(new Intent(mActivity, HomeActivity.class));
    mActivity.finish();
}

@Override
public void onSuccess(Call<Address> call, Response<Address> response) {
    mActivity.hideProgressDialog(progressDialog);
    if (response.isSuccessful()) {
        Address address = response.body();
        startHomeActivity(address);
    }
}

@Override
public void onFailure(Call<Address> call, Throwable t) {
    mActivity.hideProgressDialog(progressDialog);
}

@Override
public void onClick(View view) {
    if (view.getId() == R.id.access_location) {
        fetchAddress(mLastLocation);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_LOCATION: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
               displayLocationSettingsRequest();
            }
        }
    }
}

private void fetchAddress(Location location) {
    mRecycleService = new RecycleRetrofitBuilder(mActivity).getService();
    Call<Address> response = mRecycleService.getAddress(String.valueOf(location.getLatitude()), String.valueOf(location.getLongitude()));
    progressDialog = mActivity.showProgressDialog(mActivity);
    response.enqueue(new GetLocationCallback(AccessLocationFragment.this));
}

private void requestFineLocationPermission() {
    requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
}

private void showPermissionSnackbar() {
    GeneralDialogFragment generalDialogFragment = GeneralDialogFragment.
            newInstance("Permissions", "Allow Recycle the World to use your location.", "Allow", "Go Back", this);
    mActivity.showDialogFragment(generalDialogFragment);
    displayLocationSettingsRequest();
}

private void displayLocationSettingsRequest() {
    LocationRequest locationRequest = LocationRequest.create();
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationRequest.setInterval(10000);
    locationRequest.setFastestInterval(10000 / 2);

    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
    builder.setAlwaysShow(true);

    PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
    result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
        @Override
        public void onResult(LocationSettingsResult result) {
            final Status status = result.getStatus();
            switch (status.getStatusCode()) {
                case LocationSettingsStatusCodes.SUCCESS:
                    getLocation();
                    break;
                case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                    Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to upgrade location settings ");
                    try {
                        status.startResolutionForResult(mActivity, REQUEST_CHECK_SETTINGS);
                    } catch (IntentSender.SendIntentException e) {
                        Log.i(TAG, "PendingIntent unable to execute request.");
                    }
                    break;
                case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                    Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog not created.");
                    break;
            }
        }
    });
}

private void getLocation() {
    if (ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
            && ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CHECK_SETTINGS) {
        getLocation();
    }
}

@Override
public void onStart() {
    mGoogleApiClient.connect();
    super.onStart();
}

@Override
public void onStop() {
    mGoogleApiClient.disconnect();
    super.onStop();
}

@Override
public void onConnected(@Nullable Bundle bundle) {
    getLocation();
}

@Override
public void onDestroy() {
    super.onDestroy();
    RecycleApplication.getEventBus().unregister(this);
}


@Override
public void onConnectionSuspended(int i) {

}

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

}

@Override
public void onOk(DialogFragment dialogFragment) {
    dialogFragment.dismiss();
    requestFineLocationPermission();
}

@Override
public void onCancel(DialogFragment dialogFragment) {
    dialogFragment.dismiss();

}

}

回答1:

Sorry, I haven't go through your code, I am just writing the functions that you have asked for in your question. First, you need to build a connection to google api client like:

private synchronized void buildGoogleApiClient(){
    mGoogleApiClient = new GoogleApiClient.Builder(GTApplication.getContext())
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
    mGoogleApiClient.connect();
}

After this in my experience, you almost always get called onConnected() function where you can ask for the location permission after API level 23:

public void checkLocationPermission(){
    if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
        // You don't have the permission you need to request it 
        ActivityCompat.requestPermissions(this, Manifest.permission.ACCESS_FINE_LOCATION), REQ_CODE);
    }else{
        // You have the permission.
        requestLocationAccess();
    }
}

If you requested the permission your onRequestPermissionsResult() function will be called with the REQ_CODE. If you need more info to implement the events check the original documentation for runtime permissions it is very useful.
When you have the permission you can check if the location is enabled like:

public void requestLocationAccess(){
    LocationRequest mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval((long) (LocationHelper.UPDATE_INTERVAL_IN_MILLISECONDS*1.1));
    mLocationRequest.setFastestInterval(LocationHelper.UPDATE_INTERVAL_IN_MILLISECONDS);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    final LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest);
    builder.setAlwaysShow(true); //this is the key ingredient
    com.google.android.gms.common.api.PendingResult<LocationSettingsResult> result =
                LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
    result.setResultCallback(new ResultCallback<LocationSettingsResult>(){
        @Override
        public void onResult(@NonNull LocationSettingsResult result){
            if(requester != null){
                final Status resultStatus = result.getStatus();
                switch(resultStatus.getStatusCode()){
                    case LocationSettingsStatusCodes.SUCCESS:
                        // All location settings are satisfied. You can ask for the user's location HERE



                        break;
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        // Location settings are not satisfied. But could be fixed by showing the user a dialog.
                        try{
                            resultStatus.startResolutionForResult(this, REQUEST_LOCATION);
                            break;
                        }catch(IntentSender.SendIntentException ignored){}
                    }
                }
            }
        }
    });  
}

If the enable location dialog needed to be shown to the user you will get a callback in onActivityResult() function with the request code REQUEST_LOCATION)

That's it after you done with all this process you can call locationManager.getLastKnownLocation() or start location request or whatever you want.

PS.: I have cut this code from my bigger class, so please if you find any mistakes feel free to ask. I have specified only the case when everything goes well, because it contains the essence, you can handle the exceptions yourself I hope.



回答2:

try this code:

public void showMap() {

    mapFragment = (SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.map);
    if (map == null) {
        map = mapFragment.getMap();
    }


    // Enable Zoom
    map.getUiSettings().setZoomGesturesEnabled(true);

    //set Map TYPE
    map.setMapType(GoogleMap.MAP_TYPE_NORMAL);

    //enable Current location Button
    map.setMyLocationEnabled(true);

    LocationManager locationManager = (LocationManager)getActivity().getSystemService(getActivity().LOCATION_SERVICE);
    Criteria criteria = new Criteria();
    String bestProvider = locationManager.getBestProvider(criteria, true);
    if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }
    Location location = locationManager.getLastKnownLocation(bestProvider);
    if (location != null) {
        onLocationChanged(location);
    }
    locationManager.requestLocationUpdates(bestProvider, 2000, 0, this);
}

@Override
public void onLocationChanged(Location location) {

    latitude= location.getLatitude();
    longitude=location.getLongitude();

    LatLng loc = new LatLng(latitude, longitude);

     if (marker!=null){
         marker.remove();
     }

    marker=  map.addMarker(new MarkerOptions().position(loc).title("Sparx IT Solutions"));
    map.moveCamera(CameraUpdateFactory.newLatLng(loc));
    map.animateCamera(CameraUpdateFactory.newLatLngZoom(loc, 16.0f));

}

@Override
public void onProviderDisabled(String provider) {

    Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
    startActivity(intent);
    Toast.makeText(getActivity().getBaseContext(), "Gps is turned off!!",
            Toast.LENGTH_SHORT).show();
}

@Override
public void onProviderEnabled(String provider) {

    Toast.makeText(getActivity().getBaseContext(), "Gps is turned on!! ",
            Toast.LENGTH_SHORT).show();
}