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().
Related
I am trying to find the location using fused location library. However when I try to set text longitude and latitude in my textView, i keep on getting error. Please look into the code.
Code
private fun fetchLocation() {
val task = fusedLocationProviderClient.lastLocation
if(ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)!= PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 101)
return
}
task.addOnSuccessListener {
if(it!=null){
val longitude = findViewById<TextView>(R.id.longitude)
val latitude = findViewById<TextView>(R.id.latitude)
longitude.setText(it.longitude)
latitude.setText(it.latitude)
}
}
}
Error
<html>None of the following functions can be called with the arguments supplied:<br/>public final fun setText(text: CharSequence!): Unit defined in android.widget.TextView<br/>public final fun setText(resid: Int): Unit defined in android.widget.TextView
Because the type of longitude/latitude is Double. And the type of the parameter of setText is either Int(resId) or CharSequence.
You could convert Double to String which implements CharSequence.
longitude.setText(it.longitude.toString())
latitude.setText(it.latitude.toString())
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 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.
I'm using google maps so I need to ask some permissions.
I'm requesting the user during the onStart() of the Fragment
I'm calling requestPermissions because I'm in a fragment and I also have called super.onRequestPermissionsResult as recommended in this answer and as you can see in the code below.
I have put some breakpoint and Log to be 100% sure that onRequestPermissionsResult is not called.
class FindLessonFragment : BaseFragment(), OnMapReadyCallback, OnClusterItemClickListener<ClusterLesson>, OnClusterClickListener<ClusterLesson> {
override fun onStart() {
super.onStart()
checkPermissions()
}
private fun checkPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (activity!!.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| activity!!.checkSelfPermission(permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| activity!!.checkSelfPermission(permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
val builder = AlertDialog.Builder(activity!!)
builder.setTitle("This app needs location access")
builder.setMessage("Please grant location access so this app can work normally.")
builder.setPositiveButton(android.R.string.ok, null)
builder.setOnDismissListener {
requestPermissions(
arrayOf(permission.ACCESS_COARSE_LOCATION, permission.READ_EXTERNAL_STORAGE, permission.ACCESS_FINE_LOCATION),
PERMISSION_REQUEST_LOCATION)
}
builder.show()
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, #NonNull permissions: Array<String>, #NonNull grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
Log.e("PERMISSIONRESULT", "PASS PERMISSION RESULT")
when (requestCode) {
BaseActivity.PERMISSION_REQUEST_LOCATION -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d("BaseActivity", "coarse location permission granted")
onMapReady(mMap)
} else {
val builder = AlertDialog.Builder(context!!)
builder.setTitle("Functionality limited")
builder.setMessage(
"Since location access has not been granted, this app will not be able to work correctly.")
builder.setPositiveButton(android.R.string.ok, null)
builder.setOnDismissListener { dialog -> dialog.dismiss() }
builder.show()
}
}
}
}
companion object {
fun create() = FindLessonFragment()
internal const val PERMISSION_REQUEST_LOCATION = 1
}
}
minSdkVersion 23
Any kind of help is welcome
The onRequestPermissionsResult has to be catch in the activty.
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)