Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get current Location in GoogleMap using FusedLocationProviderClient

I want to get periodic (say every 2 minutes) current location updates for this I'm following official documentation, I wrote this code but its not giving current location updates every two minutes even specified in LocationRequest object that I'm passing in requestLocationUpdates(), here is code:

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,     GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{  private FusedLocationProviderClient FusedLocationClient; private GoogleApiClient mGoogleApiClient;  @Override protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_maps);     if (mGoogleApiClient == null) {         mGoogleApiClient = new GoogleApiClient.Builder(this)                 .addConnectionCallbacks(this)                 .addOnConnectionFailedListener(this)                 .addApi(LocationServices.API)                 .build();     }   SupportMapFragment map =    getSupportFragmentManager().findFragmentById(R.id.map));    map.getMapAsync(this);    FusedLocationClient LocationServices.getFusedLocationProviderClient(this); }   @Override public void onConnected(Bundle bundle) {     FusedLocationClient.getLastLocation()             .addOnSuccessListener(this, new OnSuccessListener<Location>() {                 @Override                 public void onSuccess(Location location) {                      if (location != null) {                         Log.i("MainActivity ", "" + location.getLongitude())                      }                 }             }); FusedLocationClient = LocationServices.getFusedLocationProviderClient(this); FusedLocationClient.requestLocationUpdates(requestLocation(),  new LocationCallback(){         @Override         public void onLocationResult(LocationResult locationResult) {             for (Location location : locationResult.getLocations()) {                Log.i("MainActivity ", "" + location.getLongitude());                //not getting current location updates every 2 minutes             }         };      },null);  }  @Override public void onConnectionSuspended(int i) {}  @Override public void onConnectionFailed(ConnectionResult connectionResult) {} 
like image 888
blackHawk Avatar asked Jul 09 '17 00:07

blackHawk


People also ask

What is the use of FusedLocationProviderClient in Android?

The FusedLocationProviderClient provides several methods to retrieve device location information. Choose from one of the following, depending on your app's use case: getLastLocation() gets a location estimate more quickly and minimizes battery usage that can be attributed to your app.

What is fused location provider client?

The fused location provider is a location API in Google Play services that intelligently combines different signals to provide the location information that your app needs.


1 Answers

This is similar to my other answer here, updated to use the recently introduced FusedLocationProviderClient class.

In order to use a FusedLocationProviderClient in conjunction with a Google Map:

  1. Wait until the Google Map is ready

  2. Request the Location permission at runtime if needed

  3. Request location updates once the permission is granted

  4. Update the Google Map once the user's location is obtained

First ensure that you're using at least version 11 of Google Play Services, as older versions don't have the FusedLocationProviderClient class (newer versions will work as well):

dependencies {       implementation 'com.google.android.gms:play-services-maps:17.0.0'       implementation 'com.google.android.gms:play-services-location:17.0.0'     //........ } 

Note that the FusedLocationProviderClient is present in version 11.0.2, but due to bugs in the initial implementation, it's recommended that you only use this class on 11.6.0 and later. From the documentation:

Note: It's recommended to use Google Play services version 11.6.0 or higher, which includes bug fixes for this class.

Add the location permissions in the AndroidManifest.xml file, inside the manifest tag and outside of the application tag:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 

Add the API key to the AndroidManifest.xml inside the application tag:

    <meta-data             android:name="com.google.android.geo.API_KEY"             android:value="AIza___YOUR_KEY_HERE______"/> 

Kotlin

Here is the full Activity class in Kotlin:

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {      lateinit var mGoogleMap: GoogleMap     var mapFrag: SupportMapFragment? = null     lateinit var mLocationRequest: LocationRequest     var mLastLocation: Location? = null     internal var mCurrLocationMarker: Marker? = null     internal var mFusedLocationClient: FusedLocationProviderClient? = null      internal var mLocationCallback: LocationCallback = object : LocationCallback() {         override fun onLocationResult(locationResult: LocationResult) {             val locationList = locationResult.locations             if (locationList.isNotEmpty()) {                 //The last location in the list is the newest                 val location = locationList.last()                 Log.i("MapsActivity", "Location: " + location.getLatitude() + " " + location.getLongitude())                 mLastLocation = location                 if (mCurrLocationMarker != null) {                     mCurrLocationMarker?.remove()                 }                  //Place current location marker                 val latLng = LatLng(location.latitude, location.longitude)                 val markerOptions = MarkerOptions()                 markerOptions.position(latLng)                 markerOptions.title("Current Position")                 markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA))                 mCurrLocationMarker = mGoogleMap.addMarker(markerOptions)                  //move map camera                 mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 11.0F))             }         }     }      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_maps)          supportActionBar?.title = "Map Location Activity"          mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)          mapFrag = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?         mapFrag?.getMapAsync(this)     }      public override fun onPause() {         super.onPause()          //stop location updates when Activity is no longer active         mFusedLocationClient?.removeLocationUpdates(mLocationCallback)     }      override fun onMapReady(googleMap: GoogleMap) {         mGoogleMap = googleMap         mGoogleMap.mapType = GoogleMap.MAP_TYPE_HYBRID          mLocationRequest = LocationRequest()         mLocationRequest.interval = 120000 // two minute interval         mLocationRequest.fastestInterval = 120000         mLocationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {             if (ContextCompat.checkSelfPermission(                     this,                     Manifest.permission.ACCESS_FINE_LOCATION                 ) == PackageManager.PERMISSION_GRANTED             ) {                 //Location Permission already granted                 mFusedLocationClient?.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper())                 mGoogleMap.isMyLocationEnabled = true             } else {                 //Request Location Permission                 checkLocationPermission()             }         } else {             mFusedLocationClient?.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper())             mGoogleMap.isMyLocationEnabled = true         }     }      private fun checkLocationPermission() {         if (ActivityCompat.checkSelfPermission(                 this,                 Manifest.permission.ACCESS_FINE_LOCATION             ) != PackageManager.PERMISSION_GRANTED         ) {             // Should we show an explanation?             if (ActivityCompat.shouldShowRequestPermissionRationale(                     this,                     Manifest.permission.ACCESS_FINE_LOCATION                 )             ) {                 // Show an explanation to the user *asynchronously* -- don't block                 // this thread waiting for the user's response! After the user                 // sees the explanation, try again to request the permission.                 AlertDialog.Builder(this)                     .setTitle("Location Permission Needed")                     .setMessage("This app needs the Location permission, please accept to use location functionality")                     .setPositiveButton(                         "OK"                     ) { _, _ ->                         //Prompt the user once explanation has been shown                         ActivityCompat.requestPermissions(                             this@MapsActivity,                             arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),                             MY_PERMISSIONS_REQUEST_LOCATION                         )                     }                     .create()                     .show()               } else {                 // No explanation needed, we can request the permission.                 ActivityCompat.requestPermissions(                     this,                     arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),                     MY_PERMISSIONS_REQUEST_LOCATION                 )             }         }     }      override fun onRequestPermissionsResult(         requestCode: Int,         permissions: Array<String>, grantResults: IntArray     ) {         when (requestCode) {             MY_PERMISSIONS_REQUEST_LOCATION -> {                 // If request is cancelled, the result arrays are empty.                 if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                      // permission was granted, yay! Do the                     // location-related task you need to do.                     if (ContextCompat.checkSelfPermission(                             this,                             Manifest.permission.ACCESS_FINE_LOCATION                         ) == PackageManager.PERMISSION_GRANTED                     ) {                          mFusedLocationClient?.requestLocationUpdates(                             mLocationRequest,                             mLocationCallback,                             Looper.myLooper()                         )                         mGoogleMap.setMyLocationEnabled(true)                     }                  } else {                      // permission denied, boo! Disable the                     // functionality that depends on this permission.                     Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show()                 }                 return             }         }// other 'case' lines to check for other         // permissions this app might request     }      companion object {         val MY_PERMISSIONS_REQUEST_LOCATION = 99     } } 

Java

Here is the full Activity class in Java:

public class MapsActivity extends AppCompatActivity         implements OnMapReadyCallback {      GoogleMap mGoogleMap;     SupportMapFragment mapFrag;     LocationRequest mLocationRequest;     Location mLastLocation;     Marker mCurrLocationMarker;     FusedLocationProviderClient mFusedLocationClient;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_maps);          getSupportActionBar().setTitle("Map Location Activity");          mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);          mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);         mapFrag.getMapAsync(this);     }      @Override     public void onPause() {         super.onPause();          //stop location updates when Activity is no longer active         if (mFusedLocationClient != null) {             mFusedLocationClient.removeLocationUpdates(mLocationCallback);         }     }      @Override     public void onMapReady(GoogleMap googleMap) {         mGoogleMap = googleMap;         mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);          mLocationRequest = new LocationRequest();         mLocationRequest.setInterval(120000); // two minute interval         mLocationRequest.setFastestInterval(120000);         mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);          if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {             if (ContextCompat.checkSelfPermission(this,                     Manifest.permission.ACCESS_FINE_LOCATION)                     == PackageManager.PERMISSION_GRANTED) {                 //Location Permission already granted                 mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());                 mGoogleMap.setMyLocationEnabled(true);             } else {                 //Request Location Permission                 checkLocationPermission();             }         }         else {             mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());             mGoogleMap.setMyLocationEnabled(true);         }     }      LocationCallback mLocationCallback = new LocationCallback() {         @Override         public void onLocationResult(LocationResult locationResult) {             List<Location> locationList = locationResult.getLocations();             if (locationList.size() > 0) {                 //The last location in the list is the newest                 Location location = locationList.get(locationList.size() - 1);                 Log.i("MapsActivity", "Location: " + location.getLatitude() + " " + location.getLongitude());                 mLastLocation = location;                 if (mCurrLocationMarker != null) {                     mCurrLocationMarker.remove();                 }                  //Place current location marker                 LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());                 MarkerOptions markerOptions = new MarkerOptions();                 markerOptions.position(latLng);                 markerOptions.title("Current Position");                 markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));                 mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);                  //move map camera                 mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 11));             }         }     };      public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;     private void checkLocationPermission() {         if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)                 != PackageManager.PERMISSION_GRANTED) {              // Should we show an explanation?             if (ActivityCompat.shouldShowRequestPermissionRationale(this,                     Manifest.permission.ACCESS_FINE_LOCATION)) {                  // Show an explanation to the user *asynchronously* -- don't block                 // this thread waiting for the user's response! After the user                 // sees the explanation, try again to request the permission.                 new AlertDialog.Builder(this)                         .setTitle("Location Permission Needed")                         .setMessage("This app needs the Location permission, please accept to use location functionality")                         .setPositiveButton("OK", new DialogInterface.OnClickListener() {                             @Override                             public void onClick(DialogInterface dialogInterface, int i) {                                 //Prompt the user once explanation has been shown                                 ActivityCompat.requestPermissions(MapsActivity.this,                                         new String[]{Manifest.permission.ACCESS_FINE_LOCATION},                                         MY_PERMISSIONS_REQUEST_LOCATION );                             }                         })                         .create()                         .show();               } else {                 // No explanation needed, we can request the permission.                 ActivityCompat.requestPermissions(this,                         new String[]{Manifest.permission.ACCESS_FINE_LOCATION},                         MY_PERMISSIONS_REQUEST_LOCATION );             }         }     }      @Override     public void onRequestPermissionsResult(int requestCode,                                            String permissions[], int[] grantResults) {         switch (requestCode) {             case MY_PERMISSIONS_REQUEST_LOCATION: {                 // If request is cancelled, the result arrays are empty.                 if (grantResults.length > 0                         && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                      // permission was granted, yay! Do the                     // location-related task you need to do.                     if (ContextCompat.checkSelfPermission(this,                             Manifest.permission.ACCESS_FINE_LOCATION)                             == PackageManager.PERMISSION_GRANTED) {                          mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());                         mGoogleMap.setMyLocationEnabled(true);                     }                  } else {                      // permission denied, boo! Disable the                     // functionality that depends on this permission.                     Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();                 }                 return;             }              // other 'case' lines to check for other             // permissions this app might request         }     } } 

activity_maps.xml:

<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout         xmlns:android="http://schemas.android.com/apk/res/android"         xmlns:tools="http://schemas.android.com/tools"         xmlns:app="http://schemas.android.com/apk/res-auto"         android:layout_width="match_parent"         android:layout_height="match_parent"         tools:context=".map.MapsActivity">      <fragment android:id="@+id/map"               xmlns:tools="http://schemas.android.com/tools"               android:layout_width="match_parent"               android:layout_height="match_parent"               tools:context=".map.MapsActivity"               app:layout_constraintTop_toTopOf="parent"               app:layout_constraintStart_toStartOf="parent"               app:layout_constraintBottom_toBottomOf="parent"               app:layout_constraintEnd_toEndOf="parent"               android:name="com.google.android.gms.maps.SupportMapFragment"/>  </androidx.constraintlayout.widget.ConstraintLayout> 

The user will be prompted to accept the Location permission:

enter image description here

The location will be updated on app launch, and every two minutes:

enter image description here

Extra note regarding AndroidX

If you are using AndroidX, you might need to add these lines to your gradle.properties file (see here for more info):

android.useAndroidX=true android.enableJetifier=true 
like image 66
Daniel Nugent Avatar answered Sep 30 '22 17:09

Daniel Nugent