so I want to get the latitude and longitude from the device, but when I build my application on android Lollipop or API 22 I'm not getting the current latitude and longitude. is this because of android permission or what? here is my code
I'm using play service location version:
implementation 'com.google.android.gms:play-services-location:17.0.0'
LocationUser.kt
class LocationUser(context: Context) {
private var fusedLocation: FusedLocationProviderClient? = null
private val INTERVAL: Long = 300000
private val FASTEST_INTERVAL: Long = 300000
private val REQUEST_LOCATION_PERMISSION = 1
lateinit var locationRequest: LocationRequest
private lateinit var lastLocation: Location
fun startLocationUpdates(context: Context) {
Log.d("LOCATION UPDATE", "started location update")
locationRequest = LocationRequest()
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locationRequest.interval = INTERVAL
locationRequest.fastestInterval = FASTEST_INTERVAL
val builder = LocationSettingsRequest.Builder()
builder.addLocationRequest(locationRequest)
val locationSettingsRequest = builder.build()
val settingsClient = LocationServices.getSettingsClient(context)
settingsClient.checkLocationSettings(locationSettingsRequest)
fusedLocation = LocationServices.getFusedLocationProviderClient(context)
if (ActivityCompat.checkSelfPermission(
context,
android.Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(
context,
android.Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
fusedLocation!!.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())
Log.d("LOCATION UPDATE", "end location update")
}
fun isPermissionGranted(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
) {
true
} else {
ActivityCompat.requestPermissions(
context as Activity, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
false
}
} else {
true
}
}
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
locationResult.lastLocation
onLocationChanged(context, locationResult.lastLocation)
super.onLocationResult(locationResult)
}
}
fun onLocationChanged(context: Context, location: Location) {
Log.d("UWUWU", "location changed")
lastLocation = location
val geocoder = Geocoder(context, Locale.getDefault())
val latitude = lastLocation.latitude
val longitude = lastLocation.longitude
val sharedPref = SharedPref(context)
Log.d("latitude", latitude.toString())
Log.d("longitude", longitude.toString())
sharedPref.saveStringPref("latitude_user", latitude.toString())
sharedPref.saveStringPref("longitude_user", longitude.toString())
try {
val addresses: List<Address> = geocoder.getFromLocation(latitude, longitude, 1)
val namaKota = addresses[0].subAdminArea
val namaKecamatan = addresses[0].locality
sharedPref.saveStringPref("alamat_user", "$namaKecamatan, $namaKota")
} catch (e: Exception) {
e.localizedMessage
}
Log.d("UWUWU", "location changed")
}
}
and in the activity I called the class like this
MainActivity.kt
class MainActivity : AppCompatActivity() {
private val REQUEST_LOCATION_PERMISSION = 1
private val REQUESTING_LOCATION_UPDATES_KEY = "requesting_location_update"
private val requestingLocationUpdates = true
val locationUser = LocationUser(this)
#SuppressLint("SimpleDateFormat", "SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
../
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
checkUserGPS()
}
if(locationUser.isPermissionGranted(this)){
locationUser.startLocationUpdates(this)
}
Log.d("GRANTED ?", locationUser.isPermissionGranted(this).toString())
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_setting, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.menu_settings) {
val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
return true
}
return super.onOptionsItemSelected(item)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
Toast.makeText(this, "permission granted", Toast.LENGTH_SHORT).show()
}
}
}
private fun checkUserGPS() {
val dialog = AlertDialog.Builder(this)
dialog.setMessage("GPS tidak aktif, apakah kamu ingin megaktifkannya?")
.setCancelable(false)
.setPositiveButton("iya") { _, which ->
startActivityForResult(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), 11)
}
.setNegativeButton("tidak") { dialog, _ ->
dialog.cancel()
finish()
}
.create()
.show()
}
override fun onResume() {
locationUser.startLocationUpdates(this)
super.onResume()
}
}
when I see log I noticed that the function of onLocationChange not called when function startLocationUpdates function is called. is this because of permission or what, I'm suffering StackOverflow and get this question which is vice versa with my problem, and I noticed the same thing which is locationcallback is not triggered
FusedLocationProviderClient requestLocationUpdates doesn't trigger LocationCallBack for API 23 above
I'm confused right now
The fused Location Provider will only maintain background location if at least one client is connected to it. Now just turning on the location service will not guarantee to store the last known location.
Once the first client connects, it will immediately try to get a location. If your activity is the first client to connect and getLastLocation() is invoked right away in onConnected(), that might not be enough time for the first location to arrive..
I suggest you to launch the Maps app first, so that there is at least some confirmed location, and then test your app.
I started to make a Kotlin app and i'm trying to access the users location. It's all my app must do. However, the function "client.requestLocationUpdates(locationRequest, locationCallback, null)" never calls my locationCallback method and I don't know why. I already debug this code, it execute the "client.requestLocationUpdates(locationRequest, locationCallback, null)" line but it never execute my LocationCallbackFunction. Here's my code:
class MainActivity : AppCompatActivity() {
private lateinit var client : FusedLocationProviderClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
client = LocationServices.getFusedLocationProviderClient(this)
}
override fun onResume() {
super.onResume()
var codigo = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this);
codigo = 0
when (codigo) {
ConnectionResult.SERVICE_MISSING,
ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED,
ConnectionResult.SERVICE_DISABLED -> {
GoogleApiAvailability.getInstance().getErrorDialog(this, codigo, 0, DialogInterface.OnCancelListener {
fun onCancel(dialog: DialogInterface?) {
finish();
}
}).show()
}
ConnectionResult.SUCCESS -> {
println("Google Play Service is working!")
}
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
println("This app hasn't permission to access users location")
return;
}
val locationRequest = LocationRequest.create()
val fifteen = 15 * 1000.toLong()
val five = 5 * 1000.toLong()
locationRequest.interval = fifteen
locationRequest.fastestInterval = five
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
var builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
var settingsClient = LocationServices.getSettingsClient(this)
settingsClient.checkLocationSettings(builder.build())
.addOnSuccessListener(
fun (locationSettingsResponse : LocationSettingsResponse) {
println("locationSettingsResponse.locationSettingsStates.isGpsPresent = ${locationSettingsResponse.locationSettingsStates.isGpsPresent}")
println("locationSettingsResponse.locationSettingsStates.isGpsUsable = ${locationSettingsResponse.locationSettingsStates.isGpsUsable}")
}
)
.addOnFailureListener(
fun (e: Exception) : Unit {
if (e is ResolvableApiException) {
try {
var resolvable : ResolvableApiException = e
resolvable.startResolutionForResult(this, 10);
} catch (e1 : IntentSender.SendIntentException ) {
}
}
}
)
val locationCallback : LocationCallback? = object : LocationCallback() {
override fun onLocationResult(locationResult : LocationResult?) {
if (locationResult == null) {
println("the value is null")
return;
}
for ( location : Location in locationResult.getLocations()) {
location.getLatitude()
println("latitude=" + location.getLatitude());
textoPrincipal.text = location.getLatitude().toString()
}
}
}
client.requestLocationUpdates(locationRequest, locationCallback, null)
}
}
That is the entire content of my activity
I solved this, and I don't know how, this exactly code is running perfectly right now. It was a error in my Android Studio configuration, I guess
I want to get the user location on button click. But it does not provide me location. I want to get user location by using android gps not with google play services
class NewPostActivity : AppCompatActivity(), LocationListener {
private val locationMangaer: LocationManager?
get() {
return getSystemService(Context.LOCATION_SERVICE) as LocationManager
}
override fun onCreate(savedInstanceState: Bundle?) {
getLocationbtn.setOnClickListener {
locationMangaer!!.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10.toFloat(), this)
}
}
override fun onLocationChanged(location: Location?) {
Log.e("data", "called")
Log.e("data", "Location is ${location!!.latitude} and ${location.latitude}")
}
}
it is all of get current location code
class MainActivity : AppCompatActivity() {
val PERMISSION_ID = 42
lateinit var mFusedLocationClient: FusedLocationProviderClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
getLastLocation()
}
#SuppressLint("MissingPermission")
private fun getLastLocation() {
if (checkPermissions()) {
if (isLocationEnabled()) {
mFusedLocationClient.lastLocation.addOnCompleteListener(this) { task ->
var location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
findViewById<TextView>(R.id.latTextView).text = location.latitude.toString()
findViewById<TextView>(R.id.lonTextView).text = location.longitude.toString()
}
}
} else {
Toast.makeText(this, "Turn on location", Toast.LENGTH_LONG).show()
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(intent)
}
} else {
requestPermissions()
}
}
#SuppressLint("MissingPermission")
private fun requestNewLocationData() {
var mLocationRequest = LocationRequest()
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
mLocationRequest.interval = 0
mLocationRequest.fastestInterval = 0
mLocationRequest.numUpdates = 1
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
mFusedLocationClient!!.requestLocationUpdates(
mLocationRequest, mLocationCallback,
Looper.myLooper()
)
}
private val mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
var mLastLocation: Location = locationResult.lastLocation
findViewById<TextView>(R.id.latTextView).text = mLastLocation.latitude.toString()
findViewById<TextView>(R.id.lonTextView).text = mLastLocation.longitude.toString()
}
}
private fun isLocationEnabled(): Boolean {
var locationManager: LocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
LocationManager.NETWORK_PROVIDER
)
}
private fun checkPermissions(): Boolean {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
return true
}
return false
}
private fun requestPermissions() {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSION_ID
)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (requestCode == PERMISSION_ID) {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
getLastLocation()
}
}
}
}
you have to add this to your ``` manifest.xml``
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
and this to your gradle
implementation 'com.google.android.gms:play-services-location:17.0.0'
I hope it will help you . happy code
I'm using google map in kotlin with help of this tutorial Introduction to Google Maps API for Android with Kotlin. in this tutorial showed how can add a marker after location updated but when it updated,there is still a marker in previous location and added again and again. there is no object of Marker in this code and i want remain first added marker and then move it. how can i do this? Thanks
class MapsActivity : AppCompatActivity(), OnMapReadyCallback,
GoogleMap.OnMarkerClickListener {
private lateinit var map: GoogleMap
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var lastLocation: Location
private lateinit var locationCallback: LocationCallback
private lateinit var locationRequest: LocationRequest
private var locationUpdateState = false
companion object {
private const val LOCATION_PERMISSION_REQUEST_CODE = 1
private const val REQUEST_CHECK_SETTINGS = 2
private const val PLACE_PICKER_REQUEST = 3
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
locationCallback = object : LocationCallback() {
override fun onLocationResult(p0: LocationResult) {
super.onLocationResult(p0)
lastLocation = p0.lastLocation
placeMarkerOnMap(LatLng(lastLocation.latitude, lastLocation.longitude))
}
}
createLocationRequest()
val fab = findViewById<FloatingActionButton>(R.id.fab)
fab.setOnClickListener {
loadPlacePicker()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CHECK_SETTINGS) {
if (resultCode == Activity.RESULT_OK) {
locationUpdateState = true
startLocationUpdates()
}
}
if (requestCode == PLACE_PICKER_REQUEST) {
if (resultCode == RESULT_OK) {
val place = PlacePicker.getPlace(this, data)
var addressText = place.name.toString()
addressText += "\n" + place.address.toString()
placeMarkerOnMap(place.latLng)
}
}
}
override fun onPause() {
super.onPause()
fusedLocationClient.removeLocationUpdates(locationCallback)
}
public override fun onResume() {
super.onResume()
if (!locationUpdateState) {
startLocationUpdates()
}
}
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
map.uiSettings.isZoomControlsEnabled = true
map.setOnMarkerClickListener(this)
setUpMap()
}
override fun onMarkerClick(p0: Marker?) = true
private fun setUpMap() {
if (ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
return
}
map.isMyLocationEnabled = true
map.mapType = GoogleMap.MAP_TYPE_NORMAL
fusedLocationClient.lastLocation.addOnSuccessListener(this) { location ->
// Got last known location. In some rare situations this can be null.
if (location != null) {
lastLocation = location
val currentLatLng = LatLng(location.latitude, location.longitude)
placeMarkerOnMap(currentLatLng)
map.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 12f))
}
}
}
private fun placeMarkerOnMap(location: LatLng) {
val markerOptions = MarkerOptions().position(location)
val titleStr = getAddress(location) // add these two lines
markerOptions.title(titleStr)
map.addMarker(markerOptions)
}
private fun startLocationUpdates() {
if (ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
LOCATION_PERMISSION_REQUEST_CODE)
return
}
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null /* Looper */)
}
private fun createLocationRequest() {
locationRequest = LocationRequest()
locationRequest.interval = 10000
locationRequest.fastestInterval = 5000
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest)
val client = LocationServices.getSettingsClient(this)
val task = client.checkLocationSettings(builder.build())
task.addOnSuccessListener {
locationUpdateState = true
startLocationUpdates()
}
task.addOnFailureListener { e ->
if (e is ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
e.startResolutionForResult(this#MapsActivity,
REQUEST_CHECK_SETTINGS)
} catch (sendEx: IntentSender.SendIntentException) {
// Ignore the error.
}
}
}
}
private fun loadPlacePicker() {
val builder = PlacePicker.IntentBuilder()
try {
startActivityForResult(builder.build(this#MapsActivity), PLACE_PICKER_REQUEST)
} catch (e: GooglePlayServicesRepairableException) {
e.printStackTrace()
} catch (e: GooglePlayServicesNotAvailableException) {
e.printStackTrace()
}
}
}
The addMarker() method of GoogleMap returns a Marker.
You need to keep a reference to the returned marker and later update it's position using the setPosition method.
#LordRaydenMK's answer is correct. I spent a week trying to work this out and found finally got it. That raywenderlich tutorial you referenced is good, except they incorrectly coded the placeMarkerOnMap() function.
First, set a variable for your location marker above onCreate:
private var userLocationMarker: Marker? = null
Then replace your placeMarkerOnMap() function with this code and it should work fine:
private fun placeMarkerOnMap(location: Location) {
val latLng = LatLng(location.latitude, location.longitude)
if (userLocationMarker == null) {
//Create a new marker
val markerOptions = MarkerOptions()
markerOptions.position(latLng)
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_user_location))
markerOptions.rotation(location.bearing)
markerOptions.anchor(0.5.toFloat(), 0.5.toFloat())
userLocationMarker = map.addMarker(markerOptions)
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 20f))
} else {
//use the previously created marker
userLocationMarker!!.position = latLng
userLocationMarker!!.rotation = location.bearing
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 20f))
}
}
If you want to get rid of the blue dot make sure to set isMyLocationEnabled to false.
I have an android application that need device current location (latitude and longitude). I've tried some tutorial on the net and specially some solutions from stack overflow, but they doesn't work well for me. My requirement is so simple: First I need it to be fast and need the location once when I the fragment starts. Second I need it to be as precise as possible, I mean it should use GPS first if GPS is not available then use Network provider.
For example, I've tried this solution but it return null after 30 second, but I know there is some all the things is ok because google map and other application works well !!!
Something that almost all the answers suggest is to use getLastKnownLocation(), but I suppose it's not the current and I don't want it if it is so.
can anyone suggest me some kind of simple and fast way to get the location just ONCE ?!
Here, you can use this...
Example usage:
public void foo(Context context) {
// when you need location
// if inside activity context = this;
SingleShotLocationProvider.requestSingleUpdate(context,
new SingleShotLocationProvider.LocationCallback() {
#Override public void onNewLocationAvailable(GPSCoordinates location) {
Log.d("Location", "my location is " + location.toString());
}
});
}
You might want to verify the lat/long are actual values and not 0 or something. If I remember correctly this shouldn't throw an NPE but you might want to verify that.
public class SingleShotLocationProvider {
public static interface LocationCallback {
public void onNewLocationAvailable(GPSCoordinates location);
}
// calls back to calling thread, note this is for low grain: if you want higher precision, swap the
// contents of the else and if. Also be sure to check gps permission/settings are allowed.
// call usually takes <10ms
public static void requestSingleUpdate(final Context context, final LocationCallback callback) {
final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (isNetworkEnabled) {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
locationManager.requestSingleUpdate(criteria, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
}
#Override public void onStatusChanged(String provider, int status, Bundle extras) { }
#Override public void onProviderEnabled(String provider) { }
#Override public void onProviderDisabled(String provider) { }
}, null);
} else {
boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (isGPSEnabled) {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
locationManager.requestSingleUpdate(criteria, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
}
#Override public void onStatusChanged(String provider, int status, Bundle extras) { }
#Override public void onProviderEnabled(String provider) { }
#Override public void onProviderDisabled(String provider) { }
}, null);
}
}
}
// consider returning Location instead of this dummy wrapper class
public static class GPSCoordinates {
public float longitude = -1;
public float latitude = -1;
public GPSCoordinates(float theLatitude, float theLongitude) {
longitude = theLongitude;
latitude = theLatitude;
}
public GPSCoordinates(double theLatitude, double theLongitude) {
longitude = (float) theLongitude;
latitude = (float) theLatitude;
}
}
}
For anyone interested in retrieving a single location update, in the best, idiomatic way, using the latest APIs, and the magic of Kotlin, here you go:
Gradle dependency:
dependencies {
...
implementation "com.google.android.gms:play-services-location:18.0.0"
...
}
Manifest permissions:
<manifest>
...
<!-- required only for LocationRequest.PRIORITY_HIGH_ACCURACY -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- required for all other priorities -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
...
</manifest>
Somewhere in your Extensions file:
// To use PRIORITY_HIGH_ACCURACY, you must have ACCESS_FINE_LOCATION permission.
// Any other priority will require just ACCESS_COARSE_LOCATION,
// but will not guarantee a location update
#SuppressLint("MissingPermission")
suspend fun FusedLocationProviderClient.awaitCurrentLocation(priority: Int): Location? {
return suspendCancellableCoroutine {
// to use for request cancellation upon coroutine cancellation
val cts = CancellationTokenSource()
getCurrentLocation(priority, cts.token)
.addOnSuccessListener {location ->
// remember location is nullable, this happens sometimes
// when the request expires before an update is acquired
it.resume(location)
}.addOnFailureListener {e ->
it.resumeWithException(e)
}
it.invokeOnCancellation {
cts.cancel()
}
}
}
In your fragment:
// need to register this anywhere before onCreateView, idealy as a field
private val permissionRequester = registerForActivityResult(
// you can use RequestPermission() contract if you only need 1 permission
ActivityResultContracts.RequestMultiplePermissions()
) { map ->
// If you requested 1 permission, change `map` to `isGranted`
// Keys are permissions Strings, values are isGranted Booleans
// An easy way to check if "any" permission was granted is map.containsValue(true)
// You can use your own logic for multiple permissions,
// but they have to follow the same checks here:
val response = map.entries.first()
val permission = response.key
val isGranted = response.value
when {
isGranted -> onPermissionGranted()
ActivityCompat.shouldShowRequestPermissionRationale(requireContext(), permission) -> {
// permission denied but not permanently, tell user why you need it.
// Idealy provide a button to request it again and another to dismiss
AlertDialog.Builder(requireContext())
.setTitle(R.string.perm_request_rationale_title)
.setMessage(R.string.perm_request_rationale)
.setPositiveButton(R.string.request_perm_again) { _, _ ->
requirePermission()
}
.setNegativeButton(R.string.dismiss, null)
.create()
.show()
}
else -> {
// permission permanently denied
// 1) tell user the app won't work as expected, or
// 2) take him to your app's info screen to manually change permissions, or
// 3) silently and gracefully degrade user experience
// I'll leave the implementation to you
}
}
}
onPermissionGranted function:
private fun onPermissionGranted() {
val lm = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
if(LocationManagerCompat.isLocationEnabled(lm)) {
// you can do this your own way, eg. from a viewModel
// but here is where you wanna start the coroutine.
// Choose your priority based on the permission you required
val priority = LocationRequest.PRIORITY_HIGH_ACCURACY
lifecycleScope.launch {
val location = LocationServices
.getFusedLocationProviderClient(requireContext())
.awaitCurrentLocation(priority)
// do whatever with this location, notice that it's nullable
}
} else {
// prompt user to enable location or launch location settings check
}
}
Now all you have to do is add this to MyLocation button click listener:
private fun requirePermission() {
val permissions = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
// optional: Manifest.permission.ACCESS_COARSE_LOCATION
)
permissionRequester.launch(permissions)
}
Note that this has the beauty of checking if the permission was already given implicitly, and not show a dialog/request if that was the case.
Ergo, always start your flow by launching the requester and only do your checks in its callback.
AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
Requesting User Permissions
build.gradle (Module: app)
dependencies {
...
implementation 'com.google.android.gms:play-services-location:15.0.0'
...
}
If you receive an error, check that your top-level build.gradle
contains a reference to the google() repo or to maven { url
"https://maven.google.com" }
Set Up Google Play Services
LocationService.kt
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.net.Uri
import android.os.Looper
import android.provider.Settings
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.ResolvableApiException
import com.google.android.gms.location.*
import org.jetbrains.anko.alert
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.okButton
object LocationService {
#SuppressLint("StaticFieldLeak")
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
doAsync {
location = locationResult.lastLocation
onSuccess(location)
}
}
}
private lateinit var onSuccess: (location : Location) -> Unit
private lateinit var onError: () -> Unit
lateinit var location: Location
fun init(activity: Activity) {
fusedLocationProviderClient = FusedLocationProviderClient(activity)
locationRequest = LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(1000).setFastestInterval(1000).setNumUpdates(1)
}
private fun checkLocationStatusAndGetLocation(activity: Activity) {
doAsync {
when {
ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED -> LocationServices.getSettingsClient(activity).checkLocationSettings(LocationSettingsRequest.Builder().addLocationRequest(locationRequest).setAlwaysShow(true).build()).addOnCompleteListener { task ->
doAsync {
try {
task.getResult(ApiException::class.java)
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
} catch (exception: ApiException) {
when (exception.statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
try {
(exception as ResolvableApiException).startResolutionForResult(activity, 7025)
} catch (ex: Exception) {
promptShowLocation(activity)
}
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
promptShowLocation(activity)
}
}
}
}
}
ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION) -> activity.runOnUiThread {
activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") {
okButton {
val ite = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", activity.packageName, null))
ite.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
activity.startActivity(ite)
onError()
}
negativeButton("Cancelar", { onError() })
onCancelled { onError() }
}.show()
}
else -> ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 7024)
}
}
}
private fun promptShowLocation(activity: Activity) {
activity.runOnUiThread {
activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") {
okButton {
activity.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
onError()
}
negativeButton("Cancelar", { onError() })
onCancelled { onError() }
}.show()
}
}
fun onRequestPermissionsResult(activity: Activity, requestCode: Int, grantResults: IntArray) {
if (requestCode == 7024) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkLocationStatusAndGetLocation(activity)
} else {
onError()
}
}
}
fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int) {
if (requestCode == 7025) {
if (resultCode == Activity.RESULT_OK) {
checkLocationStatusAndGetLocation(activity)
} else {
onError()
}
}
}
fun getLocation(activity: Activity, onSuccess: () -> Unit, onError: () -> Unit) {
this.onSuccess = onSuccess
this.onError = onError
checkLocationStatusAndGetLocation(activity)
}
}
your activity
override fun onCreate(savedInstanceState: Bundle?) {
...
LocationService.init(this)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
LocationService.onRequestPermissionsResult(this, requestCode, grantResults)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
LocationService.onActivityResult(this, requestCode, resultCode)
}
private fun yourFunction() {
LocationService.getLocation(this, { location ->
//TODO: use the location
}, {
//TODO: display error message
})
}
AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
MainActivity.java:
public class MainActivity extends AppCompatActivity implements LocationListener {
private LocationManager locationManager;
private Location onlyOneLocation;
private final int REQUEST_FINE_LOCATION = 1234;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
}
#Override public void onLocationChanged(Location location) {
onlyOneLocation = location;
locationManager.removeUpdates(this);
}
#Override public void onStatusChanged(String provider, int status, Bundle extras) { }
#Override public void onProviderEnabled(String provider) { }
#Override public void onProviderDisabled(String provider) { }
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_FINE_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d("gps", "Location permission granted");
try {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates("gps", 0, 0, this);
}
catch (SecurityException ex) {
Log.d("gps", "Location permission did not work!");
}
}
break;
}
}
What you want to do is achieved using the LocationManager#requestSingleUpdate. This method attaches a listener in a given looper (if you want or have it) and notifies the location ASAP it is received, only once. The method you suggest is used only as an inexact position before the real one is given to you.
In any case it will be fast than milliseconds (unless you are lucky enough to start listening when a location came to the device). Think on the GPS as an element that you enable when waiting for locations and disable when you remove this listening. This behavior is done to avoid draining the user's battery.
So, to sum up:
The time between you start listening and you receive the position depends on the device's GPS (manufacture, location of the user, satellite coverage...)
There is a method in the Android SDK to listen for a single update.
By providing the a criteria object, you can manage which criterias are acceptable for you to receive a location. Stronger criterias means more time to get an accurate response.
// Get LocationManager object
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// Create a criteria object to retrieve provider
Criteria criteria = new Criteria();
// Get the name of the best provider
String provider = locationManager.getBestProvider(criteria, true);
// Get Current Location
Location myLocation = locationManager.getLastKnownLocation(provider);
//latitude of location
double myLatitude = myLocation.getLatitude();
//longitude og location
double myLongitude = myLocation.getLongitude();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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;
}
All the above answers are not worked for me so I answered this
Initially add the dependencies
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
after add the class MyLocationListiner.java
package com.example.firebase_auth;
/**
* Created by Chromicle(Ajay Prabhakar).
*/
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import static android.content.Context.LOCATION_SERVICE;
public class MyLocationListener implements LocationListener {
public static double latitude;
Context ctx;
Location location;
LocationManager locationManager;
boolean isGPSEnabled = false;
boolean isNetworkEnabled = false;
public static double longitude;
MyLocationListener(Context ctx) {
this.ctx = ctx;
try {
locationManager = (LocationManager) ctx.getSystemService(LOCATION_SERVICE);
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
Toast.makeText(ctx, "GPS Enable " + isGPSEnabled, Toast.LENGTH_LONG).show();
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
Toast.makeText(ctx, "Network Enable " + isNetworkEnabled, Toast.LENGTH_LONG).show();
if ( Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission
( ctx, android.Manifest.permission.ACCESS_FINE_LOCATION )
!= PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission( ctx,
android.Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) { }
if (isGPSEnabled == true) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, this);
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
if (isNetworkEnabled==true) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, this);
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
latitude = location.getLatitude();
longitude = location.getLongitude();
// Toast.makeText(ctx,"latitude: "+latitude+" longitude: "+longitude,Toast.LENGTH_LONG).show();
}
catch(Exception ex)
{
Toast.makeText(ctx,"Exception "+ex, Toast.LENGTH_LONG).show();
}
}
#Nullable
#Override
public void onLocationChanged(Location loc)
{
loc.getLatitude();
loc.getLongitude();
latitude=loc.getLatitude();
longitude=loc.getLongitude();
}
#Override
public void onProviderDisabled(String provider)
{
//print "Currently GPS is Disabled";
}
#Override
public void onProviderEnabled(String provider)
{
//print "GPS got Enabled";
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
}
To use that class add this method
location is stored in the Address string
public void getLocation(){
Double latitude = 0.0, longitude;
String message = "";
LocationManager mlocManager = null;
LocationListener mlocListener;
mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener(this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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;
}
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
if (mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
latitude = MyLocationListener.latitude;
longitude = MyLocationListener.longitude;
message = message +"https://www.google.com/maps/dir/#"+ latitude +","+ longitude;
address=message;
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
if (latitude == 0.0) {
Toast.makeText(getApplicationContext(), "Currently gps has not found your location....", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(getApplicationContext(), "GPS is currently off...", Toast.LENGTH_LONG).show();
}
}
Hope it helpfull
I have created some classes using those you can easily get the current location. I used FusedLocationProviderClient for getting the current location.
First Add this into your manifest File:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Then Check for location permission:
private fun startCheckingLocation() {
if (checkLocationPermissions() == true) {
checkGPSEnabled()
} else {
askLocationPermission()
}
}
checkLocationPermissions method:
private fun checkLocationPermissions(): Boolean? {
return PermissionUtils.hasPermissions(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
}
checkGPSEnabled method:
private fun checkGPSEnabled() {
GpsUtils(requireContext()) {
it?.let {
startCheckingCurrentLocation()
}
}.apply {
turnGPSOn(gpsDialogCallback)
}
}
As OnActivityResult is Deprecated:
private val gpsDialogCallback = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { activityResult ->
activityResult?.let { result ->
when (result.resultCode) {
RESULT_OK -> {
startCheckingCurrentLocation()
}
RESULT_CANCELED -> {
}
}
}
}
startCheckingCurrentLocation method :
private fun startCheckingCurrentLocation() {
LocationUtils(requireContext()) { location ->
Log.d(TAG, ">>>>>>>>>>>>>>" + location.latitude + " " + location.longitude)
startIntentService(location)
}.apply {
startLocationUpdates()
}
}
For GPS I have created one class that you can simply put and use it:
GPSUtils:
class GpsUtils(
private val context: Context,
private val gpsStatus: (isEnable: Boolean?) -> Unit
) {
private val mSettingsClient: SettingsClient = LocationServices.getSettingsClient(context)
private val mLocationSettingsRequest: LocationSettingsRequest
private val locationManager: LocationManager =
context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
private val locationRequest: LocationRequest = LocationRequest.create()
init {
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locationRequest.interval = 10 * 1000.toLong()
locationRequest.fastestInterval = 2 * 1000.toLong()
val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
mLocationSettingsRequest = builder.build()
builder.setAlwaysShow(true) //this is the key ingredient
}
// method for turn on GPS
fun turnGPSOn(gpsDialogCallback: ActivityResultLauncher<IntentSenderRequest>) {
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
gpsStatus.invoke(true)
} else {
mSettingsClient
.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(
(context as Activity)
) {
// GPS is already enable, callback GPS status through listener
gpsStatus.invoke(true)
}
.addOnFailureListener(context) { e ->
when ((e as ApiException).statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
// Show the dialog by calling startResolutionForResult() and check the result in onActivityResult().
if (e is ResolvableApiException) {
try {
val intentSenderRequest = IntentSenderRequest.Builder(e.resolution).build()
gpsDialogCallback.launch(intentSenderRequest)
} catch (throwable: Throwable) {
// Ignore the error.
}
}
} catch (sie: IntentSender.SendIntentException) {
// Ignore the error.
Timber.i("PendingIntent unable to execute request.")
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
val errorMessage =
"Location settings are inadequate, and cannot be fixed here. Fix in Settings."
Timber.e(errorMessage)
}
LocationSettingsStatusCodes.CANCELED -> {
val errorMessage =
"Location settings are inadequate, and cannot be fixed here. Fix in Settings."
Timber.e(errorMessage)
}
LocationSettingsStatusCodes.SUCCESS -> {
// All location settings are satisfied. The client can initialize location
// requests here.
val errorMessage =
"Location settings are inadequate, and cannot be fixed here. Fix in Settings."
Timber.e(errorMessage)
}
}
}
}
}
}
For checking location I have created one more class :
class LocationUtils(
context: Context,
private val latLng: (location: Location) -> Unit) {
private var fusedLocationClient: FusedLocationProviderClient? = null
private val locationRequest = LocationRequest.create()?.apply {
interval = 20 * 1000.toLong()
fastestInterval = 2 * 1000.toLong()
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
init {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
}
/**
* call when location permission is allowed and you want to fetch the last location of the user
*/
fun getLastLocation() {
fusedLocationClient?.lastLocation?.addOnSuccessListener { location ->
location?.let {
latLng.invoke(location)
stopLocationUpdates()
}
}
}
/**
* Requested location callback
*/
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
for (location in locationResult.locations) {
location?.let {
latLng.invoke(it)
stopLocationUpdates()
}
}
super.onLocationResult(locationResult)
}
}
/**
* call when location permission is already given to user and you want to receive continues location updates
*/
fun startLocationUpdates() {
fusedLocationClient?.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
/**
* call when you want to stop location updates
*/
fun stopLocationUpdates() {
fusedLocationClient?.removeLocationUpdates(locationCallback)?.addOnCompleteListener { }
}
}
I have created one worker class to get the address from latlng:
class FetchAddressWorker(
context: Context,
workerParameters: WorkerParameters
) :
Worker(context, workerParameters) {
companion object {
const val TAG = "FetchAddressWorker"
}
override fun doWork(): Result {
val geoCoder = Geocoder(applicationContext, Locale.getDefault())
var errorMessage = ""
val lat: Double = inputData.getDouble(CPKConstants.LATITUDE, 0.0)
val lng: Double = inputData.getDouble(CPKConstants.LONGITUDE, 0.0)
var addresses: List<Address> = emptyList()
try {
addresses =
geoCoder.getFromLocation(lat, lng, 1)
} catch (ioException: IOException) {
// Catch network or other I/O problems.
errorMessage = "Service not available"
LogUtils.e(TAG, errorMessage, ioException)
} catch (illegalArgumentException: IllegalArgumentException) {
// Catch invalid latitude or longitude values.
errorMessage = "Invalid lat lng used"
LogUtils.e(
TAG,
"$errorMessage. Latitude = $lat , Longitude = $lng",
illegalArgumentException
)
}
// Handle case where no address was found.
if (addresses.isEmpty()) {
if (errorMessage.isEmpty()) {
errorMessage = "No Address Found"
LogUtils.e(TAG, errorMessage)
}
val data = Data.Builder()
.putString(
CPKConstants.FAILURE_RESULT,
errorMessage
)
.build()
return Result.failure(data)
} else {
val address: Address = addresses[0]
// Fetch the address lines using getAddressLine,
// join them, and send them to the thread.
val addressFragments = with(address) {
(0..maxAddressLineIndex).map { getAddressLine(it) }
}
LogUtils.i(TAG, "Address Found " + addressFragments.joinToString(separator = "\n"))
val data = Data.Builder()
.putString(
CPKConstants.SUCCESS_RESULT,
addressFragments.joinToString(separator = "\n")
)
.build()
// Indicate whether the work finished successfully with the Result
return Result.success(data)
}
}
}
Than use AddressResultReceiver in your fragment or activity:
internal inner class AddressResultReceiver(handler: Handler) : ResultReceiver(handler) {
override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
// Display the address string
// or an error message sent from the intent service.
val addressOutput = resultData?.getString(AppConstants.RESULT_DATA_KEY).orEmpty()
//displayAddressOutput()
// Show a toast message if an address was found.
if (resultCode == AppConstants.SUCCESS_RESULT) {
Boast.showText(requireContext(), "Address found = $addressOutput")
txtContinueWith.text = addressOutput
}
}
}
You will need to initialize this in fragment or activity where you will use the above receiver to get the address:
private var resultReceiver = AddressResultReceiver(Handler())
These are some constants that you should use as it is.
//Location Constants
const val LOCATION_SERVICE = "LOCATION_SERVICE"
const val SUCCESS_RESULT = 0
const val FAILURE_RESULT = 1
const val PACKAGE_NAME = "com.google.android.gms.location.sample.locationaddress"
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"
Start worker from view
private fun startAddressWorkManager(location: Location) {
val inputData = Data.Builder()
.putDouble(CPKConstants.LATITUDE, location.latitude)
.putDouble(CPKConstants.LONGITUDE, location.longitude)
.build()
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val fetchAddressWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<FetchAddressWorker>()
.setConstraints(constraints)
.setInputData(inputData)
.build()
WorkManager
.getInstance(this)
.enqueue(fetchAddressWorkRequest)
WorkManager.getInstance(this).getWorkInfoByIdLiveData(fetchAddressWorkRequest.id)
.observe(this,
{ workInfo ->
when (workInfo.state) {
WorkInfo.State.SUCCEEDED -> {
if (workInfo.state.isFinished) {
val addressData =
workInfo.outputData.getString(CPKConstants.SUCCESS_RESULT)
Timber.d("AddressData %s", addressData)
_binding?.searchEdt?.setText(addressData)
}
}
else -> {
Timber.d("workInfo %s", workInfo)
}
}
})
}