Android Google Map Displaying Current Location

The Google Map API key needs to be generated to display and place a marker at the user current location. Along with that, we also need to implement some interfaces and their callbacks methods.

Callback methods in Google Map:

OnMapRreadyCallback:

  • Invoked when its instance is set on the MapFragment object.
  • When the map is ready to be used, the onMapReady(GoogleMap) method of the OnMapReadyCallback interface is called.
  • Markers, listeners, and other attributes can be added in the onMapReady(GoogleMap) method.

LocationListener:

  • Used to receive a notification when the device location has changed.
  • When the location has changed, the LocationChanged(Location) is called which is an abstract method of LocationListener.

GoogleApiClient.ConnectionCallbacks:

  • When the device is to be connected and disconnected, the callbacks methods onConnected(Bundle) and onConnectionSuspended(int) of this interface are called.

GoogleApiClient.OnConnectionFailedListener:

  • When there is an error in connecting the device to the service, the callbacks method onConnectionFailed(ConnectionResult) of this interface is called.

setMyLocationEnabled() method:

Used to enable the location layer, to allow the device to interact with the current location.

Example of Google Map Displaying Current Location:

In the below example, we are using the Google Map to display the current location of the device.

activity_maps.xml:

In the activity_maps.xml file, we will add a SupportMapFragment in the fragment.

<?xml version="1.0" encoding="utf-8"?>  
<fragment xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:map="http://schemas.android.com/apk/res-auto"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:id="@+id/map"  
    android:name="com.google.android.gms.maps.SupportMapFragment"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    tools:context="example.com.mapexample.MapsActivity" />

build.gradle:

In the build.gradle file, we will add the below dependencies.

apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 28
 
 
    defaultConfig {
        applicationId "com.example.mapapp"
        minSdkVersion 23
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
 
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
 
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
 
}
 
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.google.android.gms:play-services-maps:11.8.0'
    implementation 'com.google.android.gms:play-services-location:11.8.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

MapsActivity.java:

In the MapsActivity.java file, we will add the below code.

package com.example.mapapp;
 
import android.os.Build;
import androidx.fragment.app.FragmentActivity;
import android.os.Bundle;
 
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.location.LocationServices;
 
import android.location.Location;
import android.Manifest;
import android.content.pm.PackageManager;
import androidx.core.content.ContextCompat;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
 
 
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
        LocationListener,GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener{
 
    private GoogleMap mMap;
    Location mLastLocation;
    Marker mCurrLocationMarker;
    GoogleApiClient mGoogleApiClient;
    LocationRequest mLocationRequest;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
 
    }
 
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
 
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                buildGoogleApiClient();
                mMap.setMyLocationEnabled(true);
            }
        }
        else {
            buildGoogleApiClient();
            mMap.setMyLocationEnabled(true);
        }
 
    }
    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API).build();
        mGoogleApiClient.connect();
    }
 
    @Override
    public void onConnected(Bundle bundle) {
 
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(1000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        }
 
    }
 
    @Override
    public void onConnectionSuspended(int i) {
 
    }
 
    @Override
    public void onLocationChanged(Location location) {
 
        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_GREEN));
        mCurrLocationMarker = mMap.addMarker(markerOptions);
 
        //move map camera
        mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
 
        //stop location updates
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
 
    }
 
    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
 
    }
 
}

AndroidManifest.xml:

To access device functionality in Android devices having Android 6.0 (Marshmallow) or later, we need some permission at runtime. To access device location, we added a runtime permission Manifest.permission.ACCESS_FINE_LOCATION, in the MapsActivity.java file. Now, we will add the below user-permission in AndroidManifest.xml file. The checkSelfPermission() method is used to check the runtime permission. It returns PackageManager.PERMISSION_GRANTED or PackageManager.PERMISSION_DENIED. The app proceeds for operation only when the permission is granted.

Required Permission:

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

File: AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="example.com.mapexample">  
    <!--  
         The ACCESS_COARSE/FINE_LOCATION permissions are not required to use  
         Google Maps Android API v2, but you must specify either coarse or fine  
         location permissions for the 'MyLocation' functionality.   
    -->  
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />  
    <uses-permission android:name="android.permission.INTERNET" />  
 
 
    <application  
        android:allowBackup="true"  
        android:icon="@mipmap/ic_launcher"  
        android:label="@string/app_name"  
        android:roundIcon="@mipmap/ic_launcher_round"  
        android:supportsRtl="true"  
        android:theme="@style/AppTheme">  
        <!--  
             The API key for Google Maps-based APIs is defined as a string resource.  
             (See the file "res/values/google_maps_api.xml").  
             Note that the API key is linked to the encryption key used to sign the APK.  
             You need a different API key for each encryption key, including the release key that is used to  
             sign the APK for publishing.  
             You can define the keys for the debug and release targets in src/debug/ and src/release/.   
        -->  
        <meta-data  
            android:name="com.google.android.geo.API_KEY"  
            android:value="@string/google_maps_key" />  
 
        <activity  
            android:name=".MapsActivity"  
            android:label="@string/title_activity_maps">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
 
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
    </application>  
 
</manifest>

Output: