I am trying to retrieve the location every 10 seconds. The problem is that the location sometimes is null, and sometimes gives back an old location. When I update the location in my emulator it is not updating live.
Code to get location:
fun checkLocation() {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
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), 1)
} else {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)
}
}
return
}
fusedLocationClient.lastLocation
.addOnSuccessListener { location : Location? ->
println("LOCATION " + location?.latitude + ", " + location?.longitude);
}
}
PermissionCheck:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
grantResults: IntArray) {
when (requestCode) {
1 -> {
if (grantResults.isNotEmpty() && grantResults[0] ==
PackageManager.PERMISSION_GRANTED) {
if ((ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) ===
PackageManager.PERMISSION_GRANTED)) {
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show()
}
return
}
}
}
Timer executed in my onCreate:
val timer = object: CountDownTimer(18000000, 10000) {
override fun onTick(millisUntilFinished: Long) {
checkLocation();
}
override fun onFinish() {}
}
timer.start()
Output:
I/System.out: LOCATION 37.4219752, -122.0839923
While my new location is somewhere totally else. Even after restarting the app. Is there a way to request the app/device to get the new location?
You cannot rely on lastLocation completely , lastLocation can be null
Also lastLocation will return the device last known location so it will not update as the device location updates until and unless some other app is requesting location (like google map)
lastLocation literally means that we are not requesting for new Location, instead we are using location which are requested by other apps, so the lastLocation can be null or old
https://developer.android.com/training/location/retrieve-current
So Instead of relying on lastLocation use requestLocationUpdates, using which you can set the time interval like after how much time you want to receive the new location, so you don't have to implement CountDownTimer
I think for your case requestLocationUpdates will be the best option
Read below docs for how to request Location updates
https://developer.android.com/training/location/request-updates
This is in Addition to #Shobhith's Answer above.
When working with the emulator it doesn't update the location immediately thus the reason for returning the old location.
To get around this you need to set the location in the emulator
Then open Map Application (already installed in the emulator) and press the My Location Button to force the emulator to update the location.
Related
Here's my code:
private var longitude = ""
private var latitude = ""
In the oncreateView, I have to do a api call with my latitude and longitude data. But the value of latitude and longitude never change!
//location
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(requireActivity())
// getCurrentLocation
checkPermissions()
//CALL API
val request = Request.Builder()
.url(" API_PATH?latitude=$latitude&longitude=$longitude")
.build()
val client = OkHttpClient()
...
private fun checkPermissions(){
if(ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_DENIED){
ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 1)
}
else{
getLocations()
}
}
private fun getLocations() {
if (ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
requireContext(),
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
}
fusedLocationProviderClient.lastLocation.addOnCompleteListener {
if(it == null){
Toast.makeText(requireContext(), "sorry can't get the location", Toast.LENGTH_SHORT).show()
}else it.apply {
latitude = it.result.latitude.toString()
longitude = it.result.longitude.toString()
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode== 1){
if(grantResults.isNotEmpty() && grantResults[0]==PackageManager.PERMISSION_GRANTED){
//permission granted
if(ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED){
Toast.makeText(requireContext(), "Permission granted", Toast.LENGTH_SHORT).show()
getLocations()
}
}else{
Toast.makeText(requireContext(), "Permission denied", Toast.LENGTH_SHORT).show()
//denied permission
}
}
}
First, I enter always in th first condition in checkPermissions(). I don't know why. Secondly, I also try to write getLocations() in the first condition in the first if in checkPermissions(). But longitude and latitude are never update.
Can you help me please, I am on this case for a long time and I have no idea.
I think you always enter the first condition in checkPermissions() because you haven't yet granted the permissions.
I think you need to request the permissions where the TODO code is commented out.
It will be something like:
// You can directly ask for the permission.
requestPermissions(CONTEXT,
arrayOf(Manifest.permission.REQUESTED_PERMISSION),
REQUEST_CODE)
Found from https://developer.android.com/training/permissions/requesting
I hope that steers you in the right direction.
If you want to cheat for testing, you can go to Settings -> Apps -> Your app -> Permissions and enable the permissions and then re-test. Of course, you'll have to do the request in code for the users of your app before you release the app.
i am trying to get user's location using only GPS provider. i don't want my app to get the last known location or request for location updates after a particular period of time or when location is changed.is there any way that can give me current location on button press ??? ... i am a beginner, i have tried LocationManager API from android studio and it returns network provided location fine but dosent work when using GPS . here is my code :
fun getlocation() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION), locationPermissionCode)
}
else
{
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
// val listener = locationListener()
val gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
val network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
//if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N)
if (gps || network) {
if (network) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 5F, this)
}
if (gps) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 5F, this)
}
}
else {
val AlertDialog = AlertDialog.Builder(this)
AlertDialog.setTitle("GPS is Disabled")
AlertDialog.setMessage("Do you want enable GPS ?")
AlertDialog.setPositiveButton("Yes") { dialougeInterface: DialogInterface, i: Int ->
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(intent)
dialougeInterface.dismiss()
}
AlertDialog.setNegativeButton("No") { dialouge: DialogInterface, i: Int ->
dialouge.dismiss()
}
AlertDialog.show()
}
}
}
i have added location listener in the parent class " class AddCustomer : AppCompatActivity() , LocationListener "
in override function :
override fun onLocationChanged(location: Location) {
locationx.text = location.latitude.toString() +" , "+ location.longitude.toString()
}
should i use "getcurrentlocation()" method from "LocationManager" ?
I don't know if you are getting your last location or not. Here's the answer when you are not getting anything at all from the gps provider.
Making this block like this will only make you get your location via gps.
if (gps) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 5F, this)
}
The above can return when your device's GPS chipset feels like it's getting signal from the GPS, so when inside a building, it will likely be not getting any responds.
Go outside and try it out.
In your usecase, pressing a button to get an accurate location, in case the user can't receive any signal, you should provide a callback for timeout.
private val mHandler = Handler(Looper.getMainLooper())
private val mTimeoutRunnable = Runnable {
//stopLoading
//Toast the user to try it somewhere else
}
fun askGsp() {
mHandler.postDelayed(mTimeoutRunnable, 5 * 1000) //time out in 5 seconds
//ask for gps update like the code above
//...
override fun onLocationChanged(location: Location) {
mHandler.removeCallbacks(mTimeoutRunnable) //remove timeout action
locationx.text = location.latitude.toString() +" , "+
location.longitude.toString()
}
}
Hi i have permission check on my forYou fragment when the app starts start and you give the permission and it makes a api call and get the weather for you current location the problem is I must switch the fragment for getting the call and switch again for showing it in the reclyerview the problem is when I give the permission for the location it doesn't do the api after that, I must refresh the fragment
fusedLocationClient.lastLocation.addOnSuccessListener(requireActivity()) { location ->
if (location != null) {
currentLocation = location
val currentLatLng = LatLng(location.latitude, location.longitude)
val currentAddress = getAddress(location.latitude, location.longitude)
Log.d("TAG", "klagenfurt : ${currentAddress}")
retrofitOneCallResponse(location.latitude, location.longitude, currentAddress)
dataService.getFavorites(this)
}
}
if (ActivityCompat.checkSelfPermission(
requireContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
MapViewFragment.LOCATION_PERMISSION_REQUEST_CODE
)
return
}
enter image description here
HERE it says and you write the code without ActivityCompat on the requestpermisson line it doesn't work etiher
Create one method like this.
private fun getLocation(){
fusedLocationClient.lastLocation.addOnSuccessListener(requireActivity()) { location ->
if (location != null) {
currentLocation = location
val currentLatLng = LatLng(location.latitude, location.longitude)
val currentAddress = getAddress(location.latitude, location.longitude)
Log.d("TAG", "klagenfurt : ${currentAddress}")
retrofitOneCallResponse(location.latitude, location.longitude, currentAddress)
dataService.getFavorites(this)
}else{
getLocation()
}
}
}
then from here
if (ActivityCompat.checkSelfPermission(
requireContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
requestPermissions(
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
MapViewFragment.LOCATION_PERMISSION_REQUEST_CODE
)
}else{
getLocation()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray): Unit {
if(requestCode==MapViewFragment.LOCATION_PERMISSION_REQUEST_CODE){
if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
getLocation();
}
}
}
Also, override the onRequestPermissionsResult in the fragment. and check if permission granted the call getLocation().
In my Android Application I am targeting the device ranging from,
Minimum Android Version - 7.1 (API 25)
Target Android Version - 10.0 (API 29)
I am using the below logic to get the location Information
Permissions Using
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Code Logic
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
gps_loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
network_loc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
} catch (Exception e) {
e.printStackTrace();
}
if (gps_loc != null) {
final_loc = gps_loc;
latitude = final_loc.getLatitude();
longitude = final_loc.getLongitude();
}
else if (network_loc != null) {
final_loc = network_loc;
latitude = final_loc.getLatitude();
longitude = final_loc.getLongitude();
}
else {
latitude = 0.0;
longitude = 0.0;
}
}
But most of the time I am not getting accurate location with API call. But If enable the below option in device level (in Phone), I am getting the most accurate location
Is there any way I can configure the above settings in application level through code. The client which I am working is not satisfied with changing the configuration manually.
I am wondering how I can achieve the same through code. Someone please help.
Somethings you should know about getLastKnownLocation(...) [From Document]
Gets the last known location from the given provider, or null if there is no last known location. The returned location may be quite old in some circumstances, so the age of the location should always be checked.
This will never activate sensors to compute a new location, and will only ever return a cached location.
Please try locationManager.requestSingleUpdate(...), this method will request user current location.
if(locationManager.allProviders.contains(LocationManager.GPS_PROVIDER)) {
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, locListener)
} else if(locationManager.allProviders.contains(LocationManager.NETWORK_PROVIDER)){
locationManager.rerequestSingleUpdate(LocationManager.NETWORK_PROVIDER, locListener)
}
And this is listener.
val locListener = object: LocationListener {
override fun onLocationChanged(location: Location?) {
// do something with updated location here.
}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onProviderEnabled(provider: String?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onProviderDisabled(provider: String?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
I'm trying to get Location information using getLastKnownLocation but I often get null.
Here is what I do:
Turn OFF location in Settings
Run my app - getLastKnownLocation returns null - this is expected
Turn ON location in Settings
Run my app again - getLastKnownLocation returns null !?
Run Google Maps
Run my app again - getLastKnownLocation returns a valid Location !?
I found this question where the accepted answer suggests to launch Maps first in order to get the location:
FusedLocationApi.getLastLocation always null
The questions is: what is Google Maps doing to get the location? And how can I do the same in my code?
Thanks!
Thanks everyone for the help!
I was missing uses-features declarations in my manifest - thanks #CommonsWare for the link: https://developer.android.com/guide/topics/location/strategies.html#java
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.location.network" />
Also, requesting updates like this is needed as well:
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
In my case the GPS provider needs a few minutes to connect and start sending data - the Network provider seems to be faster but does not always work - so I'll use both of them.
Update: a few key points
It's not really intuitive, but in order to get data from getLastKnownLocation some app on the device - be it Google Maps or our own app - needs to call requestLocationUpdates.
Some providers might not be enabled on a particular device - so it's a good idea to use both the GPS_PROVIDER and the NETWORK_PROVIDER - or use all enabled providers: locationManager.getProviders(true)
Here is the code I ended up using:
for ( String provider : locationManager.getProviders(true) ) {
setLocation( locationManager.getLastKnownLocation(provider) );
locationManager.requestLocationUpdates(provider, Tools.MIN_5, 0, locationListener);
}
// call setLocation again in locationListener.onLocationChanged
here is a code chunk which may help you.
if (!::mFusedLocationProviderClient.isInitialized) {
mFusedLocationProviderClient = FusedLocationProviderClient(mContext)
mLocationRequest = LocationRequest()
mLocationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
mLocationRequest.interval = 10000
mLocationRequest.fastestInterval = 5000
mLocationRequest.smallestDisplacement = 1000 * 100f
}
if (ActivityCompat.checkSelfPermission(
AppName.appContext,
android.Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
AppName.appContext,
android.Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
// not enough permission
return
}
mFusedLocationProviderClient.requestLocationUpdates(mLocationRequest, object : LocationCallback() {
override fun onLocationResult(p0: LocationResult?) {
super.onLocationResult(p0)
mFusedLocationProviderClient.removeLocationUpdates(this)
if (p0 != null) {
//here is your location
} else {
// location is null
}
}
override fun onLocationAvailability(p0: LocationAvailability?) {
if(p0?.isLocationAvailable!= true){
//location not available.
}
}
}, Looper.getMainLooper())
make sure you give all permission and if you run app above 6.1 device then handle permission..
after that used this code..
add below dependency into app level gradle file..
//Place API
implementation 'com.google.android.gms:play-services-places:16.0.0'
implementation 'com.google.android.gms:play-services-location:16.0.0'
define this into class level as global deceleration.
private lateinit var fusedLocationClient: FusedLocationProviderClient
private var context: Context? = null
private var locationCallback: LocationCallback? = null
private var locationRequest: LocationRequest? = null
private var googleApiClient: GoogleApiClient? = null
after that onCreate method..
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
make method for getting location..
fun getCurrentLocation() {
// Get Current location and do reverse geocoding
ProgressUtils.showOldProgressDialog(this)
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
ProgressUtils.closeOldProgressDialog()
for (location in locationResult.locations) {
// here you get current lat ,long,etc value..
stopLocationUpdates()
}
} catch (e: Exception) {
e.message.loggerError()
stopLocationUpdates()
}
}
}
}
locationRequest = LocationRequest().apply {
interval = 10000
fastestInterval = 5000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
startLocationUpdates()
}
make location update..
fun startLocationUpdates() {
googleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.build()
googleApiClient!!.connect()
val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest!!)
builder.setAlwaysShow(true)
val result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build())
result.setResultCallback { result ->
val status = result.status
when (status.statusCode) {
LocationSettingsStatusCodes.SUCCESS -> {
Log.i(TAG, "All location settings are satisfied.")
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)
}
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to upgrade location settings ")
try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(this, LOCATION_SETTING_REQUEST_CODE)
} catch (e: IntentSender.SendIntentException) {
Log.i(TAG, "PendingIntent unable to execute request.")
}
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog not created.")
}
}
}
make method for stop location..
private fun stopLocationUpdates() {
if (locationCallback != null) {
fusedLocationClient?.removeLocationUpdates(locationCallback)
}
}
override fun onStop() {
super.onStop()
stopLocationUpdates()
}
override fun onPause() {
super.onPause()
stopLocationUpdates()
}
if handle permission than permission is grant then call back getting onActivity Result method there put below code..
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)