Tutorial ini membahas mengenai bagaimana membuat rute terdekat dari lokasi menggunakan google map, dimana untuk menentukan rute terdekat dari lokasi tersebut membutuhkan API
dari Google Developers
anda bisa membaca dokumentasi dibagian sini.
Java - Menentukan Rute Terdekat dari Lokasi menggunakan Google Map
Sebelum Anda mulai membuat proyek ini, Anda membutuhkan API keys
supaya aplikasi dapat berjalan dengan Google Maps, untuk membuat Google Maps API key disini
API
yang digunakan untuk membuat rute terdekat dari lokasi, yang dimana untuk output format menggunakan json.
http://maps.googleapis.com/maps/api/directions/json?parameters
Dari API diatas ada parameter yang harus diprelukan antara lain:
origin
- Lokasi asal dengan mengisikan berupa alamat, nilai dari garis lintang (Latitude
) dan bujur (Longitude
) atauID
tempat dimana anda ingin menentukan rute.- Jika anda mengisikan berupa alamat anda perlu memasukan pada parameter
origin
origin=Mataram
- Jika anda mengisikan dengan nilai lintang dan bujur anda harus memasukan bagian parameter
origin
origin=-8.594848, 116.105390
- Jika anda mengisikan dengan nilai ID anda harus memasukan bagian parameter
origin
origin=place_id:DhIJSS-JXXauEmsRUcIaWtf5MzE
- Jika anda mengisikan berupa alamat anda perlu memasukan pada parameter
destination
- Lokasi tujuan dengan mengisikan berupa alamat, nilai dari garis lintang (Latitude
) dan bujur (Longitude
) atauID
, untuk opsi destination hampirsama pengisian denganorigin
.key
- Kunci API aplikasi yang harus anda buat untuk ditempatkan di parameter key
Menyiapkan Proyek
Langkah pertama masukan dependencies
dibagian file build gradle
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.google.android.gms:play-services-maps:16.1.0'
implementation 'com.google.android.gms:play-services-location:16.0.0'
implementation 'com.google.android.gms:play-services-places:16.0.0'
implementation 'com.google.android.libraries.places:places-compat:1.1.0'
implementation 'com.google.maps.android:android-maps-utils:0.5+'
Download resource disini dan tempatkan dibagain drawable
Langkah Membuat Proyek
Bagian Manifests
Masukan Api Keys
dibagain value
dari metadata
.
.....
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application
.....
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOU HERE KEYS" />
<service
android:name=".service.FetchAddressIntentService"
android:exported="false"/>
</application>
Menambahkan Permission GPS
, fungsinya saat aplikasi dijalankan akan tampil dialog untuk meminta mengaktifkan GPS
.
package com.kodetr.googlemap.utils
import android.app.Activity
import android.content.Context
import android.content.IntentSender
import android.location.LocationManager
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.api.GoogleApiClient
import com.google.android.gms.common.api.PendingResult
import com.google.android.gms.common.api.Status
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.LocationSettingsRequest
import com.google.android.gms.location.LocationSettingsResult
import com.google.android.gms.location.LocationSettingsStatusCodes
/**
* Created by kodetr on 09/05/19.
*/
class PermissionGPS(private val activity: Activity) {
private var googleApiClient: GoogleApiClient? = null
init {
// Todo Location Already on ... start
val manager = activity.getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(activity)) {
// Toast.makeText(activity, "Gps already enabled", Toast.LENGTH_SHORT).show();
}
// Todo Location Already on ... end
if (!hasGPSDevice(activity)) {
Toast.makeText(activity, "Gps tidak mendukung", Toast.LENGTH_SHORT).show()
}
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(activity)) {
Log.e("TAG", "Gps already enabled")
enableLoc()
} else {
Log.e("TAG", "Gps already enabled")
}
}
private fun hasGPSDevice(context: Context): Boolean {
val mgr = context
.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val providers = mgr.allProviders ?: return false
return providers.contains(LocationManager.GPS_PROVIDER)
}
private fun enableLoc() {
if (googleApiClient == null) {
googleApiClient = GoogleApiClient.Builder(activity)
.addApi(LocationServices.API)
.addConnectionCallbacks(object : GoogleApiClient.ConnectionCallbacks {
override fun onConnected(bundle: Bundle?) {
}
override fun onConnectionSuspended(i: Int) {
googleApiClient!!.connect()
}
})
.addOnConnectionFailedListener { connectionResult -> Log.d("Location error", "Location error " + connectionResult.errorCode) }.build()
googleApiClient!!.connect()
}
val locationRequest = LocationRequest.create()
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locationRequest.interval = (30 * 1000).toLong()
locationRequest.fastestInterval = (5 * 1000).toLong()
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest)
builder.setAlwaysShow(true)
val result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build())
result.setResultCallback { result1 ->
val status = result1.status
when (status.statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
status.startResolutionForResult(activity, REQUEST_LOCATION)
} catch (e: IntentSender.SendIntentException) {
}
}
}
}
companion object {
internal const val REQUEST_LOCATION = 199
}
}
Membuat validasi supaya terhubung ke jaringan internet dengan membuat fungsi check koneksi, kasusnya jika terhubung ke jaringan maka aplikasi diteruskan jika tidak maka keluar dari aplikasi dengan popup “Kesalahan jariangn periksa koneksi anda”.
package com.kodetr.googlemap.utils
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkInfo
/**
* Created by kodetr on 18/05/19.
*/
object Connections {
fun checkConnection(context: Context): Boolean {
val connMgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetworkInfo = connMgr.activeNetworkInfo
if (activeNetworkInfo != null) {
if (activeNetworkInfo.type == ConnectivityManager.TYPE_WIFI) {
// connected to wifi
return true
} else if (activeNetworkInfo.type == ConnectivityManager.TYPE_MOBILE) {
// connected to the mobile provider's data plan
return true
}
}
return false
}
}
Selanjutnya membuat penampungan konstan, jadi anda tidak menginginkan anda bisa menerapkan langsung pada aplikasi anda.
package com.kodetr.googlemap.utils
/**
* Created by kodetr on 19/05/19.
*/
object Constants {
const val DIRECTION_URL_API = "https://maps.googleapis.com/maps/api/directions/json?"
private const val PACKAGE_NAME = "com.kodetr.googlemap"
const val RECEIVER = "$PACKAGE_NAME.RECEIVER"
const val RESULT_DATA_KEY = "$PACKAGE_NAME.RESULT_DATA_KEY"
const val LOCATION_DATA_EXTRA = "$PACKAGE_NAME.LOCATION_DATA_EXTRA"
const val SUCCESS_RESULT = 0
const val FAILURE_RESULT = 1
}
Membuat aksi dimana digunakan untuk mengambil alamat menggunakan intent
dengan menerima berupa result
dari lokasi yang ditentukan oleh kordinat blue point
pada GPS
, untuk menerapkannya dengan membuat Intent Service
dan menjalankan dengan memanggil service
pada manifest
yang sudah diterapkan pada langkah sebelumnya.
package com.kodetr.googlemap.service
import android.app.IntentService
import android.content.Intent
import android.location.Address
import android.location.Geocoder
import android.location.Location
import android.os.Bundle
import android.os.ResultReceiver
import android.text.TextUtils
import android.util.Log
import com.kodetr.googlemap.R
import com.kodetr.googlemap.utils.Constants
import java.io.IOException
import java.util.ArrayList
import java.util.Locale
/**
* Asynchronously handles an intent using a worker thread. Receives a ResultReceiver object and a
* location through an intent. Tries to fetch the address for the location using a Geocoder, and
* sends the result to the ResultReceiver.
*/
/**
* This constructor is required, and calls the super IntentService(String)
* constructor with the name for a worker thread.
*/
class FetchAddressIntentService : IntentService(TAG) {
/**
* The receiver where results are forwarded from this service.
*/
private var receiver: ResultReceiver? = null
/**
* Tries to get the location address using a Geocoder. If successful, sends an address to a
* result receiver. If unsuccessful, sends an error message instead.
* Note: [ResultReceiver] in * MainActivity is defined to
* process the content sent from this service.
*
*
* This service calls this method from the default worker thread with the intent that started
* the service. When this method returns, the service automatically stops.
*/
override fun onHandleIntent(intent: Intent?) {
var errorMessage = ""
receiver = intent!!.getParcelableExtra(Constants.RECEIVER)
if (receiver == null) {
Log.wtf(TAG, "No receiver received. There is nowhere to send the results.")
return
}
val location = intent.getParcelableExtra<Location>(Constants.LOCATION_DATA_EXTRA)
if (location == null) {
errorMessage = getString(R.string.no_location_data_provided)
Log.wtf(TAG, errorMessage)
deliverResultToReceiver(Constants.FAILURE_RESULT, errorMessage)
return
}
val geocoder = Geocoder(this, Locale.getDefault())
var addresses: List<Address>? = null
try {
addresses = geocoder.getFromLocation(
location.latitude,
location.longitude,
1)
} catch (ioException: IOException) {
errorMessage = getString(R.string.service_not_available)
Log.e(TAG, errorMessage, ioException)
} catch (illegalArgumentException: IllegalArgumentException) {
errorMessage = getString(R.string.invalid_lat_long_used)
Log.e(TAG, errorMessage + ". " +
"Latitude = " + location.latitude +
", Longitude = " + location.longitude, illegalArgumentException)
}
if (addresses == null || addresses.isEmpty()) {
deliverResultToReceiver(Constants.FAILURE_RESULT, errorMessage)
} else {
val address = addresses[0]
val addressFragments = ArrayList<String>()
for (i in 0..address.maxAddressLineIndex) {
addressFragments.add(address.getAddressLine(i))
}
Log.i(TAG, getString(R.string.address_found))
deliverResultToReceiver(Constants.SUCCESS_RESULT,
TextUtils.join(System.getProperty("line.separator")!!, addressFragments))
}
}
/**
* Sends a resultCode and message to the receiver.
*/
private fun deliverResultToReceiver(resultCode: Int, message: String) {
val bundle = Bundle()
bundle.putString(Constants.RESULT_DATA_KEY, message)
receiver!!.send(resultCode, bundle)
}
companion object {
private const val TAG = "FetchAddressIS"
}
}
Selanjutnya adalah membuat Parsing
data dari url API
dengan menggunakan lib json
, Membuat model berupa interfece finder listener, class model Distance, class model Duration dan class model Route.
class Distance(var text: String, var value: Int)
class Duration(var text: String, var value: Int)
class Route {
var distance: Distance? = null
var duration: Duration? = null
var endAddress: String? = null
var endLocation: LatLng? = null
var startAddress: String? = null
var startLocation: LatLng? = null
var points: List<LatLng>? = null
}
interface DirectionFinderListener {
fun onDirectionFinderStart()
fun onDirectionFinderSuccess(route: List<Route>)
}
Menerapkan Parsing
data dari url API
dengan menggunakan lib json
.
package com.kodetr.googlemap.models.direction
import android.annotation.SuppressLint
import android.os.AsyncTask
import com.google.android.gms.maps.model.LatLng
import com.kodetr.googlemap.utils.Constants
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import java.io.UnsupportedEncodingException
import java.net.MalformedURLException
import java.net.URL
import java.net.URLEncoder
import java.util.ArrayList
/**
* Created by kodetr on 09/05/19.
*/
class DirectionFinder(private val listener: DirectionFinderListener, private val origin: String, private val destination: String) {
fun execute(google_api_key: String) {
listener.onDirectionFinderStart()
DownloadRawData().execute(createUrl(google_api_key))
}
private fun createUrl(google_api_key: String): String {
val urlOrigin = URLEncoder.encode(origin, "utf-8")
val urlDestination = URLEncoder.encode(destination, "utf-8")
return Constants.DIRECTION_URL_API + "origin=" + urlOrigin + "&destination=" + urlDestination + "&key=" + google_api_key
}
@SuppressLint("StaticFieldLeak")
private inner class DownloadRawData : AsyncTask<String, Void, String>() {
override fun doInBackground(vararg params: String): String? {
val link = params[0]
try {
val url = URL(link)
val `is` = url.openConnection().getInputStream()
val buffer = StringBuilder()
val reader = BufferedReader(InputStreamReader(`is`))
while (reader.readLine() != null) {
buffer.append(reader.readLine()).append("\n")
}
return buffer.toString()
} catch (e: MalformedURLException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
return null
}
override fun onPostExecute(res: String) {
try {
parseJSon(res)
} catch (e: JSONException) {
e.printStackTrace()
}
}
}
private fun parseJSon(data: String?) {
if (data == null)
return
val routes = ArrayList<Route>()
val jsonData = JSONObject(data)
val jsonRoutes = jsonData.getJSONArray("routes")
for (i in 0 until jsonRoutes.length()) {
val jsonRoute = jsonRoutes.getJSONObject(i)
val route = Route()
val overview_polylineJson = jsonRoute.getJSONObject("overview_polyline")
val jsonLegs = jsonRoute.getJSONArray("legs")
val jsonLeg = jsonLegs.getJSONObject(0)
val jsonDistance = jsonLeg.getJSONObject("distance")
val jsonDuration = jsonLeg.getJSONObject("duration")
val jsonEndLocation = jsonLeg.getJSONObject("end_location")
val jsonStartLocation = jsonLeg.getJSONObject("start_location")
route.distance = Distance(jsonDistance.getString("text"), jsonDistance.getInt("value"))
route.duration = Duration(jsonDuration.getString("text"), jsonDuration.getInt("value"))
route.endAddress = jsonLeg.getString("end_address")
route.startAddress = jsonLeg.getString("start_address")
route.startLocation = LatLng(jsonStartLocation.getDouble("lat"), jsonStartLocation.getDouble("lng"))
route.endLocation = LatLng(jsonEndLocation.getDouble("lat"), jsonEndLocation.getDouble("lng"))
route.points = decodePolyLine(overview_polylineJson.getString("points"))
routes.add(route)
}
listener.onDirectionFinderSuccess(routes)
}
}
Menambahkan fungsi decode untuk setiap poin yang ditampung dalam list berupa langitude dan longitude untuk mencari rute paling dominan dengan menampilkan berupa garis pada map.
private fun decodePolyLine(poly: String): List<LatLng> {
val len = poly.length
var index = 0
val decoded = ArrayList<LatLng>()
var lat = 0
var lng = 0
while (index < len) {
var b: Int
var shift = 0
var result = 0
do {
b = poly[index++].toInt() - 63
result = result or (b and 0x1f shl shift)
shift += 5
} while (b >= 0x20)
val dlat = if (result and 1 != 0) (result shr 1).inv() else result shr 1
lat += dlat
shift = 0
result = 0
do {
b = poly[index++].toInt() - 63
result = result or (b and 0x1f shl shift)
shift += 5
} while (b >= 0x20)
val dlng = if (result and 1 != 0) (result shr 1).inv() else result shr 1
lng += dlng
decoded.add(LatLng(lat / 100000.0, lng / 100000.0))
}
return decoded
}
Jika anda sudah mengikuti langkah dengan benar maka struktur akan seperti gambar berikut.
Bagian activity
utama yaitu MapsActivity
yang harus anda terapkan terlebih dahulu, berupa Permission
dan cek Connection
.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkLocationPermission()
}
if (!Connections.checkConnection(this)) {
Toast.makeText(this, "Kesalahan jaringan periksa koneksi anda", Toast.LENGTH_SHORT).show()
finish()
}
Buat request permission dari fungsi checkLocationPermission
beserta dengan fungsi popup
.
private fun checkLocationPermission(): Boolean {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
MY_PERMISSIONS_REQUEST_LOCATION)
} else {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
MY_PERMISSIONS_REQUEST_LOCATION)
}
return false
} else {
return true
}
}
Membuat fungsi untuk pencarian menggunakan Auto Complete
dengan penerapan pada parameter url API
sebagai destination
.
private fun setupAutoCompleteFragment() {
val autocompleteFragment = fragmentManager.findFragmentById(R.id.place_autocomplete_fragment) as PlaceAutocompleteFragment
autocompleteFragment.setOnPlaceSelectedListener(object : PlaceSelectionListener {
override fun onPlaceSelected(place: Place) {
searchLocation = place.latLng
}
override fun onError(status: Status) {
Log.e("Error", status.statusMessage)
}
})
}
Mencari rute terdekat dengan melakukan aksi pada fungsi DirectionFinder
dengan memasukan parameter origin
, destination
dan api key
kedalam fungsi tersebut.
DirectionFinder(MapsActivity.this, origin, destination , api_key);
Menerapkan proses Direction Finder
untuk menampilkan distance
dan duration
dengan origin
dari blue poin
ke destination
yang ditandai dengan marker
merah dengan menampilkan berupa garis dengan warna merah.
override fun onDirectionFinderSuccess(routes: List<Route>) {
progressDialog!!.dismiss()
polyLinePaths = ArrayList()
originMarkers = ArrayList()
destinationMarker = ArrayList()
for (route in routes) {
map!!.moveCamera(CameraUpdateFactory.newLatLngZoom(route.startLocation, 15.5f))
(findViewById<View>(R.id.tvDistance) as TextView).text = route.distance!!.text
(findViewById<View>(R.id.tvTime) as TextView).text = route.duration!!.text
destinationMarker!!.add(map!!.addMarker(MarkerOptions()
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))
.title(route.endAddress)
.position(route.endLocation!!)))
val polylineOptions = PolylineOptions()
.geodesic(true)
.color(resources.getColor(R.color.colorPrimary))
.width(10f)
for (i in route.points!!.indices) {
polylineOptions.add(route.points!![i])
}
polyLinePaths!!.add(map!!.addPolyline(polylineOptions))
}
}
Lebih jelasnya ada bisa melihat vidio diatas dan jika langkah-langkah diatas sudah diikuti dengan benar untuk source code
lengkapnya seperti dibawah.
package com.kodetr.googlemap
import android.Manifest
import android.annotation.SuppressLint
import android.app.ProgressDialog
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Geocoder
import android.location.Location
import android.os.*
import android.support.design.widget.FloatingActionButton
import android.support.design.widget.Snackbar
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.View
import android.widget.TextView
import android.widget.Toast
import com.google.android.gms.common.api.Status
import com.google.android.gms.location.*
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.MapFragment
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.model.*
import com.google.android.libraries.places.compat.Place
import com.google.android.libraries.places.compat.ui.PlaceAutocompleteFragment
import com.google.android.libraries.places.compat.ui.PlaceSelectionListener
import com.kodetr.googlemap.models.direction.DirectionFinder
import com.kodetr.googlemap.models.direction.DirectionFinderListener
import com.kodetr.googlemap.models.direction.Route
import com.kodetr.googlemap.service.FetchAddressIntentService
import com.kodetr.googlemap.utils.Connections
import com.kodetr.googlemap.utils.Constants
import com.kodetr.googlemap.utils.PermissionGPS
import java.util.*
/**
* Created by kodetr on 09/05/19.
*/
class MapsActivity : AppCompatActivity(), GoogleMap.OnMarkerClickListener, GoogleMap.OnMapClickListener, OnMapReadyCallback, DirectionFinderListener {
private val LocationA = LatLng(-8.594848, 116.105390)
private var map: GoogleMap? = null
private var fusedLocationProvider: FusedLocationProviderClient? = null
private var locationRequest: LocationRequest? = null
private var locationCallback: LocationCallback? = null
private var locationgps: Location? = null
private var resultReceiver: ResultReceiver? = null
private var selectedMarker: Marker? = null
private var searchLocation: LatLng? = null
private var originMarkers: List<Marker>? = ArrayList()
private var destinationMarker: MutableList<Marker>? = ArrayList()
private var polyLinePaths: MutableList<Polyline>? = ArrayList()
private var progressDialog: ProgressDialog? = null
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkLocationPermission()
}
if (!Connections.checkConnection(this)) {
Toast.makeText(this, "Kesalahan jaringan periksa koneksi anda", Toast.LENGTH_SHORT).show()
finish()
}
init()
fusedLocationProvider = LocationServices.getFusedLocationProviderClient(this)
resultReceiver = object : ResultReceiver(Handler()) {
override fun onReceiveResult(resultCode: Int, resultData: Bundle) {
val addressOutput = resultData.getString(Constants.RESULT_DATA_KEY)
Toast.makeText(applicationContext, addressOutput, Toast.LENGTH_SHORT).show()
}
}
locationgps = Location("Point A")
}
@SuppressLint("SetTextI18n")
private fun init() {
setupAutoCompleteFragment()
val fa = findViewById<FloatingActionButton>(R.id.fblocation)
fa.setOnClickListener {
try {
val origin = locationgps!!.latitude.toString() + "," + locationgps!!.longitude
DirectionFinder(this@MapsActivity, origin, searchLocation!!.latitude.toString() + "," + searchLocation!!.longitude).execute(getString(R.string.google_maps_key))
} catch (e: Exception) {
e.printStackTrace()
}
}
val ft = findViewById<FloatingActionButton>(R.id.fbsatelit)
ft.setOnClickListener {
if (map != null) {
val MapType = map!!.mapType
if (MapType == 1) {
ft.setImageResource(R.drawable.ic_satellite_off)
map!!.mapType = GoogleMap.MAP_TYPE_SATELLITE
} else {
ft.setImageResource(R.drawable.ic_satellite_on)
map!!.mapType = GoogleMap.MAP_TYPE_NORMAL
}
}
}
val fm = findViewById<FloatingActionButton>(R.id.fbgps)
fm.setOnClickListener {
getDeviceLocation(true)
if (!Geocoder.isPresent()) {
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_SHORT).show()
} else {
showAddress()
}
}
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
if (locationResult == null)
return
for (locationUpdate in locationResult.locations) {
locationgps = locationUpdate
if (gpsFirstOn) {
gpsFirstOn = false
getDeviceLocation(true)
}
}
}
}
locationRequest = LocationRequest()
locationRequest!!.interval = UPDATE_INTERVAL
locationRequest!!.fastestInterval = FASTEST_UPDATE_INTERVAL
locationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
val mapFragment = fragmentManager.findFragmentById(R.id.map) as MapFragment
mapFragment.getMapAsync(this)
}
private fun setupAutoCompleteFragment() {
val autocompleteFragment = fragmentManager.findFragmentById(R.id.place_autocomplete_fragment) as PlaceAutocompleteFragment
autocompleteFragment.setOnPlaceSelectedListener(object : PlaceSelectionListener {
override fun onPlaceSelected(place: Place) {
searchLocation = place.latLng
}
override fun onError(status: Status) {
Log.e("Error", status.statusMessage)
}
})
}
override fun onMapReady(gMap: GoogleMap) {
map = gMap
map!!.setOnMapClickListener(this)
map!!.setOnMarkerClickListener(this)
map!!.moveCamera(CameraUpdateFactory.newLatLngZoom(LocationA, DEFAULT_ZOOM))
map!!.uiSettings.isMapToolbarEnabled = false
map!!.uiSettings.isMyLocationButtonEnabled = false
// map.getUiSettings().setCompassEnabled(false);
// TODO : location
map!!.projection.visibleRegion
if (!checkPermission())
requestPermission()
getDeviceLocation(false)
}
override fun onDirectionFinderStart() {
progressDialog = ProgressDialog.show(this, "Tunggu sebentar", "Mencari lokasi terdekat..", true)
if (originMarkers != null) {
for (marker in originMarkers!!) {
marker.remove()
}
}
if (destinationMarker != null) {
for (marker in destinationMarker!!) {
marker.remove()
}
}
if (polyLinePaths != null) {
for (polylinePath in polyLinePaths!!) {
polylinePath.remove()
}
}
}
override fun onDirectionFinderSuccess(routes: List<Route>) {
progressDialog!!.dismiss()
polyLinePaths = ArrayList()
originMarkers = ArrayList()
destinationMarker = ArrayList()
for (route in routes) {
map!!.moveCamera(CameraUpdateFactory.newLatLngZoom(route.startLocation, 15.5f))
(findViewById<View>(R.id.tvDistance) as TextView).text = route.distance!!.text
(findViewById<View>(R.id.tvTime) as TextView).text = route.duration!!.text
destinationMarker!!.add(map!!.addMarker(MarkerOptions()
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))
.title(route.endAddress)
.position(route.endLocation!!)))
val polylineOptions = PolylineOptions()
.geodesic(true)
.color(resources.getColor(R.color.colorPrimary))
.width(10f)
for (i in route.points!!.indices) {
polylineOptions.add(route.points!![i])
}
polyLinePaths!!.add(map!!.addPolyline(polylineOptions))
}
}
private fun getDeviceLocation(MyLocation: Boolean) {
if (!MyLocation)
if (checkPermission()) {
if (map != null)
map!!.isMyLocationEnabled = true
val locationResult = fusedLocationProvider!!.lastLocation
locationResult.addOnCompleteListener(this) { task ->
if (task.isSuccessful && task.result != null) {
// lastKnownLocation = task.getResult();
} else {
Log.w(TAG, "getLastLocation:exception", task.exception)
Toast.makeText(this, R.string.no_location_detected, Toast.LENGTH_SHORT).show()
}
}
} else
Log.d(TAG, "Current location is null. Permission Denied.")
}
override fun onMapClick(point: LatLng) {
selectedMarker = null
}
override fun onMarkerClick(marker: Marker): Boolean {
if (marker == selectedMarker) {
selectedMarker = null
return true
}
Toast.makeText(this, marker.title, Toast.LENGTH_SHORT).show()
selectedMarker = marker
return false
}
private fun showAddress() {
val intent = Intent(this, FetchAddressIntentService::class.java)
intent.putExtra(Constants.RECEIVER, resultReceiver)
intent.putExtra(Constants.LOCATION_DATA_EXTRA, locationgps)
startService(intent)
}
override fun onStart() {
super.onStart()
if (Connections.checkConnection(this)) {
PermissionGPS(this)
}
}
override fun onRestart() {
super.onRestart()
if (Connections.checkConnection(this)) {
PermissionGPS(this)
}
}
override fun onResume() {
super.onResume()
if (Connections.checkConnection(this)) {
if (checkPermission())
fusedLocationProvider!!.requestLocationUpdates(locationRequest, locationCallback!!, Looper.myLooper())
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
Log.i(TAG, "onRequestPermissionResult")
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
when {
grantResults.isEmpty() -> Log.i(TAG, "User interaction was cancelled.") // grantResults.length > 0
grantResults[0] == PackageManager.PERMISSION_GRANTED -> getDeviceLocation(false)
else -> showSnackbar(R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE, android.R.string.ok
) { requestPermission() }
}
}
}
private fun showSnackbar(textStringId: Int, length: Int, actionStringId: Int, listener: (Any) -> Unit) {
val snackbar = Snackbar.make(findViewById(android.R.id.content), textStringId, length)
snackbar.setAction(actionStringId, listener)
snackbar.show()
}
private fun requestPermission() {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
}
private fun checkPermission(): Boolean {
return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
private fun checkLocationPermission(): Boolean {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
MY_PERMISSIONS_REQUEST_LOCATION)
} else {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
MY_PERMISSIONS_REQUEST_LOCATION)
}
return false
} else {
return true
}
}
companion object {
private val TAG = MapsActivity::class.java.simpleName
private const val DEFAULT_ZOOM = 9.5f
private const val UPDATE_INTERVAL: Long = 500
private const val FASTEST_UPDATE_INTERVAL = UPDATE_INTERVAL / 5
private const val LOCATION_PERMISSION_REQUEST_CODE = 1
private var gpsFirstOn = true
const val MY_PERMISSIONS_REQUEST_LOCATION = 99
}
}
Hasil Output
Hasil akhirnya anda bisa lihat gambar dibawah.
Demikian yang dapat saya sampaikan dari artikel ini semoga bermanfaat, jika anda mengalami kesulitan anda bisa melihat vidio yang sudah disediakan atau melalui komentar dibawah, selamat mencoba.