LBS - Penjelasan Kode Mendapatkan Lokasi Detil Perangkat Saat Ini

Bagian ini akan menjelaskan bagian-bagian kode yang penting dari app 'CurrentPlaceDetailsOnMap', pada latihan sebelumnya, sehingga kita bisa memahami bagaimana membuat app yang sejenis.

Membuat Google API client

Kita perlu membuat instans dari untuk API client dari Google Play services (atau disebut juga dengan Google API client) sehingga kita bisa terkoneksi dengan provider lokasi gabungan dan Google Places API for Android.

Latihan yang sudah kita buat sebelumnya akan menjelaskan kode yang kita perlukan untuk berinteraksi dengan Google API client. Untuk lebih detil tentang petunjuk untuk mengakses Google API bisa dilihat di link ini: https://developers.google.com/android/guides/api-client#Starting

1. Kita deklarasikan variabel untuk Google API client di dalam class 'MapsActivityCurrentPlaces':
private GoogleApiClient mGoogleApiClient;
2. Kita panggil/build Google API client di dalam method 'onCreate()'. Ini untuk me-request provider lokasi gabungan (LocationServices.API) dan dua bagian dari Google Places API for Android (Places.GEO_DATA_API dan Places.PLACE_DETECTION_API):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* ... tempat kode lainnya... */
// Build the Play services client for use by the Fused Location Provider and the Places API.
buildGoogleApiClient();
mGoogleApiClient.connect();
}
berikut adalah kode dari method 'buildGoogleApiClient()':
private synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */,
this /* OnConnectionFailedListener */)
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.build();
createLocationRequest();
}
Untuk method 'createLocationRequest()' akan dijelaskan nanti dibawah.
Catatan:
Kita tidak perlu membat Google API client bila kita hanya menggunakan Google Maps Android API.

Request location permission

App kita harus melakukan request untuk location permission untuk menentukan lokasi perangkat dan mengijinkan user men-tap tombol My Location di peta.

Latihan yang sudah kita buat sebelumnya sudah memberikan kode yang kita perlukan untuk me-request 'fine location permission'. Untuk petunjuk lebih detil tentang Android permission bisa dilihat di link ini:https://developer.android.com/training/permissions/requesting.html

1. Kita tambahkan permission di file 'Androidmanifest.xml' di dalam elemen seperti berikut ini:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.currentplacedetailsonmap">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
....

</manifest>
2. Kita buat request runtime permission di dalam app kita, sehingga memberi user kesempatan untuk mengijinkan atau menolak location permission. Kode berikut akan men-cek apakah user memberikan permission atau tidak. 
private void getDeviceLocation() {
if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mLocationPermissionGranted = true;
} else {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
}
// A step later in the tutorial adds the code to get the device
// location.
}
3. Kita override method 'onRequestPermissionResult()' untuk menangani hasil dari permission request:
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String permissions[],
@NonNull int[] grantResults) {
mLocationPermissionGranted = false;
switch (requestCode) {
case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mLocationPermissionGranted = true;
}
}
}
updateLocationUI();
}
4. Kita tulisakan method 'updateLocationUI()' untuk menentukan kontrol lokasi di peta. Bila user memberikan location permission, My Location akan muncul, sebaliknya tidak akan muncul dan akan menetukan lokasi saat ini ke null:
private void updateLocationUI() {
if (mMap == null) {
return;
}

if (mLocationPermissionGranted) {
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(true);
} else {
mMap.setMyLocationEnabled(false);
mMap.getUiSettings().setMyLocationButtonEnabled(false);
mCurrentLocation = null;
}
}

Mendapatkan lokasi perangkat Android

Kita akan menggunakan fused location provider untuk menemukan lokasi perangkat saat ini dan me-request update secara regular bila perangkat bergerak ke lokasi baru.

Latihan sebelumnya sudah memberikan kode yang kita perlukan untuk menemukan lokasi perangkat saat ini. Untuk petunjuk lebih detil tentang fused location provider dari Google Play services location APIs bisa dibaca di link ini: https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi

1. Kita buat satu object untuk membuat request lokasi:
private 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);
}
2. Kita re-quest lokasi terakhir dari perangkat, dan me-register untuk update lokasi:
private void getDeviceLocation() {
/*
* Before getting the device location, you must check location
* permission, as described earlier in the tutorial. Then:
* Get the best and most recent location of the device, which may be
* null in rare cases when a location is not available.
* Also request regular updates about the device location.
*/
if (mLocationPermissionGranted) {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
}
}
3. Meng-update method bila lokasi berubah, untuk men-set ke lokasi perangkat saat ini dan meng-update informasi yang ditampilkan di peta. Untuk penjelasan method 'updatemarkers()' akan dijelaskan nanti di bawah.
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
updateMarkers();
}

Menambahkan map/peta:

Kita akan menampilkan map/peta dengan menggunakan Google Maps Android API.

1. Kita tambahkan elemen ke file layout activity, 'activity_maps.xml'. Elemen ini akan mendefinisikan 'SupportMapFragment' untuk bertindak sebagai kontainer map/peta dan menyediakan akses ke object GoogleMap. 
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
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="com.example.currentplacedetailsonmap.MapsActivityCurrentPlaces" />
2. Di dalam method 'onCreate()' di activity kita, tetapkan file layout tersebut untuk menampilkan isi app kita:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
}
3. Kita implementasikan interface 'OnMapReadyCallback' dan me-override method 'onMapReady()', untuk mengatur map/peta ketika object GoogleMap sudah ada:
public class MapsActivityCurrentPlaces extends AppCompatActivity implements
OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
/**
* Manipulates the map when it's available.
* This callback is triggered when the map is ready to be used.
*/
@Override
public void onMapReady(GoogleMap map) {
mMap = map;
// Do other setup activities here too.
}
}
4. Di dalam activity kita pada method 'onConnected()', kita ambil fragment peta/map dengan memanggil 'FragmentManager.findFragmentById()'. Kemudian kita gunakan 'getMapAsync()' untuk me-register map:
@Override
public void onConnected(Bundle connectionHint) {
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}

Menemukan lokasi terdekat dan menampilkannya dengan marker di map/peta

Kita gunakan Google Places API for Android untuk menampilkan titik-titik utama yang terdekat. Dalam latihan ini sudah ada kode yang kita perlukan untuk berinteraksi dengan Google Places API for Android. Untuk petunjuk lebih detil bagaimana mendpatkan lokasi saat ini bisa dibaca di link ini: https://developers.google.com/places/android-api/current-place

1. Kita buat method 'updateMarkers()' untuk mendapatkan daftar lokasi yang dekat dengan lokasi perangkat saat ini dan menambahkan marker pada masing-masing lokasi. Isi marker akan meliputi nama dan alamat lokasi:
private void updateMarkers() {
if (mMap == null) {
return;
}

if (mLocationPermissionGranted) {
// Get the businesses and other points of interest located
// nearest to the device's current location.
@SuppressWarnings("MissingPermission")
PendingResult result = Places.PlaceDetectionApi
.getCurrentPlace(mGoogleApiClient, null);
result.setResultCallback(new ResultCallback() {
@Override
public void onResult(@NonNull PlaceLikelihoodBuffer likelyPlaces) {
for (PlaceLikelihood placeLikelihood : likelyPlaces) {
// Add a marker for each place near the device's current location, with an
// info window showing place information.
String attributions = (String) placeLikelihood.getPlace().getAttributions();
String snippet = (String) placeLikelihood.getPlace().getAddress();
if (attributions != null) {
snippet = snippet + "\n" + attributions;
}

mMap.addMarker(new MarkerOptions()
.position(placeLikelihood.getPlace().getLatLng())
.title((String) placeLikelihood.getPlace().getName())
.snippet(snippet));
}
// Release the place likelihood buffer.
likelyPlaces.release();
}
});
} else {
mMap.addMarker(new MarkerOptions()
.position(mDefaultLocation)
.title(getString(R.string.default_info_title))
.snippet(getString(R.string.default_info_snippet)));
}
}
2. Kita buat custom layout untuk menampilkan info. Ini akan memungkinkan untuk menampilkan beberapa baris isi dalam tampilan info. Pertama, kita tambahkan file layout XML 'custom_info_contents.xml', yang berisi textview untuk judul info, dan textview lainnya untuk snippet (yaitu, isi info):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layoutDirection="locale"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textColor="#ff000000"
android:textStyle="bold" />

<TextView
android:id="@+id/snippet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff7f7f7f" />
</LinearLayout>

3. Kita implementasikan interface 'InfoWindowAdapter' untuk menampilkan isi info ke depan:
@Override
public void onMapReady(GoogleMap map) {
// Do other setup activities here too.
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {

@Override
// Return null here, so that getInfoContents() is called next.
public View getInfoWindow(Marker arg0) {
return null;
}

@Override
public View getInfoContents(Marker marker) {
// Inflate the layouts for the info window, title and snippet.
View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_contents, null);

TextView title = ((TextView) infoWindow.findViewById(R.id.title));
title.setText(marker.getTitle());

TextView snippet = ((TextView) infoWindow.findViewById(R.id.snippet));
snippet.setText(marker.getSnippet());

return infoWindow;
}
});
Catatan:
Secara default, Google Maps Android API menampilkan isi info bila user men-tap marker. Tidak perlu ada click listener untuk marker bila kita sudah puas menggunakan versi default.

Menyimpan status map/peta

Kita menyimpan posisi kamera dan lokasi perangkat. Bila user me-rotasi perangkat Androidnya, atau mengubah konfigurasi, Android akan men-destroy dan membuat ulang map activity tersebut. Untuk memastikan user experience yang nyaman, baiknya kita menyimpan status app yang elevan dan memuat ulang ketika diperlukan.

Latihan sebelumnya sudah menuliskan kode yang kita perlukan untuk menyimpan status map. 

1. Di dalam map activity, kita tentukan nilai konstanta untuk menyimpan status activity:
private static final String KEY_CAMERA_POSITION = "camera_position";
private static final String KEY_LOCATION = "location";
2. Kita implementasikan method 'onSaveInstanceState()' untuk menyimpan status ketika activity di-pause:
@Override
protected void onSaveInstanceState(Bundle outState) {
if (mMap != null) {
outState.putParcelable(KEY_CAMERA_POSITION, mMap.getCameraPosition());
outState.putParcelable(KEY_LOCATION, mCurrentLocation);
super.onSaveInstanceState(outState);
}
}
3. Di dalam method 'onCreate()' pada activity, kita muat ulang lokasi perangkat dan posisi kamera bila sudah disimpan sebelumnya:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mCurrentLocation = savedInstanceState.getParcelable(KEY_LOCATION);
mCameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
}
}
4. Di dalam method 'onMapReady()', kita tetapkan posisi kamera map/peta ke posisi sebelumnya bila sudah disimpan sebelumnya.
@Override
public void onMapReady(GoogleMap map) {
mMap = map;
// Do other setup activities here too.
/*
* Set the map's camera position to the current location of the device.
* If the previous state was saved, set the position to the saved state.
* If the current location is unknown, use a default position and zoom value.
*/
if (mCameraPosition != null) {
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPosition));
} else if (mCurrentLocation != null) {
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(mCurrentLocation.getLatitude(),
mCurrentLocation.getLongitude()), DEFAULT_ZOOM));
} else {
Log.d(TAG, "Current location is null. Using defaults.");
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
mMap.getUiSettings().setMyLocationButtonEnabled(false);
}
}
Selesai. Sampai disini kita sudah belajar membuat app Android yang menampilkan lokasi terdekat pada Google map. Kita juga telah mempelajari bagaimana menggunakan Google Maps Android API, Google Places API for Android, dan fused location provider.

sumber: https://developers.google.com/maps/documentation/android-api/current-places-tutorial
license: cc by

No comments: