Get current location Android Kotlin - android

I try to get the current Location with GM API in my application (using Android Studio). But if i click the button which triggers the getLocation() funktion, i always end up in the catch{} block and i dont know why.
My mobile device is connected for testing.
Here is the getLocation() Funktion:
fun getLocation() {
var locationManager = getSystemService(LOCATION_SERVICE) as LocationManager?
var locationListener = object : LocationListener{
override fun onLocationChanged(location: Location?) {
var latitute = location!!.latitude
var longitute = location!!.longitude
Log.i("test", "Latitute: $latitute ; Longitute: $longitute")
}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
}
override fun onProviderEnabled(provider: String?) {
}
override fun onProviderDisabled(provider: String?) {
}
}
try {
locationManager!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0L, 0f, locationListener)
} catch (ex:SecurityException) {
Toast.makeText(applicationContext, "Fehler bei der Erfassung!", Toast.LENGTH_SHORT).show()
}
}
Here is the onCreate Funktion:
class CurrentLocationActivity : AppCompatActivity() {
lateinit var mapFragment : SupportMapFragment
lateinit var googleMap : GoogleMap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_current_location)
//Karte erstellen
mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(OnMapReadyCallback {
googleMap = it
})
//OnClickListener um Location zu speichern
btnGetCurrentLocation.setOnClickListener {
getLocation()
}
}

Try as follow
Step 1. Put on your AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com....">
<!-- This line -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application ... />
</manifest>
Step 2. Put it above your location request
import android.Manifest
import android.content.pm.PackageManager
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
...
fun getLocation() {
...
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSION_REQUEST_ACCESS_FINE_LOCATION)
return
}
locationManager!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0L, 0f, locationListener)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_REQUEST_ACCESS_FINE_LOCATION) {
when (grantResults[0]) {
PackageManager.PERMISSION_GRANTED -> getLocation()
PackageManager.PERMISSION_DENIED -> //Tell to user the need of grant permission
}
}
}
companion object {
private const val PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 100
}

The LocationManager will throw a SecurityException if the location permission has not been granted.
Information on adding the location permissions to your app can be found here.

Related

Retrieving Coarse Location to retrieve Lat and Lon values

I apologize in advance for any of the amateur moves that I've made in the code below. This is my first Android app. It's a weather app and I am trying to implement a button that will retrieve the local weather based on where the phone is located. After tapping the button, the user will first be asked to allow location permission (coarse location), and then I'm attempting to use FusedLocationProviderClient to retrieve the latitude and longitude, which can then be used to make an api call to get the weather data. This is for a class, so I'm required to use something close to the approach I'm attempting to take in my code.
I'm 99% sure I have the location permission portion of the code working correctly. I've been running the app through the debugger and based on the path it's following, the permission is being requested and then is showing as permission granted when it should be showing as such. My problem is that something is wrong with the code that retrieves location data for the lat and lon values. I can see in the debugger that they are still null when I try to send them to the view model for the api call. (I've marked the line where I get a NullPointerException in the fragment below -- it's about 2/3 of the way down the file.)
One important thing that is worth noting: I have a red error line under "override" in this code in the fragment:
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
super.onLocationResult(locationResult)
for (location in locationResult.locations) {
lat = location.latitude.toString()
lon = location.longitude.toString()
}
}
}
I have seen this basic code setup in several examples, so I'm assuming it doesn't always have the red line. The error says "onLocationResult overrides nothing." If I remove the question mark on that line, the red line goes away, but I don't know if doing that is part of what is causing my problem. I suspect that this code is the problem since I don't think the app ever gets to the lines that assign values to lat and lon. For the record, this is how I have to modify the code to get rid of the red line so the app can run (question mark removed and line after it removed, but I just commented it out here):
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
//locationResult ?: return
super.onLocationResult(locationResult)
for (location in locationResult.locations) {
lat = location.latitude.toString()
lon = location.longitude.toString()
}
}
}
I've been looking at videos and reading answers on Stack Overflow for most of the day and haven't found anything that quite matches what I'm trying to do here. I've tried moving different methods from Activity to Fragment and back again. It always seems to come down to I'm simply not pulling in the location data properly to get those lat/lon values. At this point, I'm just hoping to find people who know more than I do to look at the code and see if something obvious is wrong. I feel like it might be something minor, but I could be wrong.
MainActivity:
package com.example.weatherapp
import android.Manifest
import android.app.AlertDialog
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.app.ActivityCompat
import com.example.weatherapp.databinding.ActivityMainBinding
import dagger.hilt.android.AndroidEntryPoint
#AndroidEntryPoint
class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback {
private val apiKey = "5025177c6bd1ce93f4ffa221fd7f7c8c"
private val REQUEST_LOCATION_PERMISSION = 1234
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
fun requestLocationPermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_COARSE_LOCATION)
) {
showLocationPermissionRationale()
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
}
}
private fun showLocationPermissionRationale() {
AlertDialog.Builder(this)
.setMessage(R.string.location_permission_rationale)
.setNeutralButton(R.string.ok) { _, _ ->
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
}
.create()
.show()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission granted - Should I have something here??
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
}
SearchFragment:
package com.example.weatherapp
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Looper
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import com.example.weatherapp.databinding.FragmentSearchBinding
import com.google.android.gms.location.*
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
#AndroidEntryPoint
class SearchFragment : Fragment() {
private lateinit var binding: FragmentSearchBinding
#Inject lateinit var searchViewModel: SearchViewModel
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback
private var lat: String? = null
private var lon: String? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(activity as MainActivity)
locationRequest = LocationRequest.create()
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
super.onLocationResult(locationResult)
for (location in locationResult.locations) {
lat = location.latitude.toString()
lon = location.longitude.toString()
}
}
}
binding = FragmentSearchBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
requireActivity().title = "Search"
searchViewModel.enableButton.observe(this) { enable ->
binding.button.isEnabled = enable
}
searchViewModel.showErrorDialog.observe(this) { showError ->
if (showError) {
ErrorDialogFragment().show(childFragmentManager, ErrorDialogFragment.TAG)
}
}
binding.zipCode.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
p0?.toString()?.let { searchViewModel.updateZipCode(it) }
}
override fun afterTextChanged(p0: Editable?) {
}
})
binding.button.setOnClickListener {
searchViewModel.submitButtonClicked()
if(!(searchViewModel.showErrorDialog.value!!)) {
val currentConditionsArg = SearchFragmentDirections.searchToCurrent(
searchViewModel.currentConditions.value,
searchViewModel.returnZipCode(),
null,
null
)
Navigation.findNavController(it).navigate(currentConditionsArg)
} else {
searchViewModel.resetErrorDialog()
}
}
// New location code starts here:
binding.localWeatherButton.setOnClickListener {
if (ContextCompat.checkSelfPermission(
(activity as MainActivity), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
startLocationUpdates()
searchViewModel.localWeatherButtonClicked(lat!!, lon!!) <- lat/lon still NULL!
if(!(searchViewModel.showErrorDialog.value!!)) {
val currentConditionsArg = SearchFragmentDirections.searchToCurrent(
searchViewModel.currentConditions.value,
null,
lat,
lon
)
Navigation.findNavController(it).navigate(currentConditionsArg)
} else {
searchViewModel.resetErrorDialog()
}
} else {
(activity as MainActivity).requestLocationPermission()
}
}
}
private fun startLocationUpdates() {
if (ContextCompat.checkSelfPermission(activity as MainActivity,
Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
} else {
// permission not granted (though it should be since we wouldn't get here if it wasn't...)
}
}
}

how to create a service or process that updates location in background when application is in background?

i need a method to continuously get location updates in my application even when my application is in background. i have tried using Service and BroadcastReceiver but when application goes into background, location updates are stopped.
here is my Code with boradcast Receiver:-
MainActivity:
class MainActivity : AppCompatActivity() {
companion object {
private var instance: MainActivity? = null
fun getMainInstance(): MainActivity? {
return instance
}
}
private lateinit var client: FusedLocationProviderClient
private lateinit var request: LocationRequest
#RequiresApi(Build.VERSION_CODES.M)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
instance = this
client = LocationServices.getFusedLocationProviderClient(applicationContext)
request = LocationRequest.create()
request.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
request.interval = 1000
request.fastestInterval = 1000
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
requestPermissions(
arrayOf(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION
), 2201
)
} else {
client.requestLocationUpdates(request, getPendingIntent()!!)
}
}
override fun onPause() {
super.onPause()
Toast.makeText(applicationContext, "paused", Toast.LENGTH_SHORT).show()
}
override fun onStop() {
super.onStop()
Toast.makeText(applicationContext, "stopped", Toast.LENGTH_SHORT).show()
}
override fun onDestroy() {
super.onDestroy()
client.removeLocationUpdates(getPendingIntent()!!)
Toast.makeText(applicationContext, "destroyed", Toast.LENGTH_SHORT).show()
}
fun toastMessage(location: String) {
this.runOnUiThread {
Toast.makeText(
this,
location,
Toast.LENGTH_SHORT
).show()
}
}
private fun getPendingIntent(): PendingIntent? {
val intent = Intent(this,MyLocationReceiver::class.java)
intent.setAction(MyLocationReceiver.ACTION_PROCESS_UPDATE)
return PendingIntent.getBroadcast(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT)
}
}
BroadcastReceiver:
class MyLocationReceiver : BroadcastReceiver() {
companion object{
val ACTION_PROCESS_UPDATE = "com.example.backgroundlocation.UPDATE_LOCATION"
}
override fun onReceive(context: Context?, intent: Intent?) {
if(intent != null) {
val action = intent.action
if (action.equals(ACTION_PROCESS_UPDATE) && LocationResult.hasResult(intent)){
val locationResult = LocationResult.extractResult(intent)
try {
Log.d("onLocationReceived", locationResult.toString())
//MainActivity.getMainInstance()?.toastMessage(locationResult.toString())
} catch (e: Exception) {
Toast.makeText(context, e.toString(), Toast.LENGTH_SHORT).show()
}
} else {
//MainActivity.getMainInstance()?.toastMessage("no result")
}
}
}
}
to me, the solution to this seems impossible.
Is there any way to update location when application is in background ? Kindly help me out!
To access the location while in the background you need to get this permission as well from the user in the Manifest
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
While giving the permission user needs to select allow all the time for location.

Unable to get data from Intent in Activity

I am very new to Kotlin and Android Development and really wanting to get into it. I am doing a project to help me understand and work with intent. The goal is simple, an android app that gets the users location in one activity, then passes it on to the next activity, where I intend to use it ( in the form of longitude and latitude). However I have been trying for hours to get the data to pass as an extra. The error that is show says nullpointer:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Intent.getStringExtra(java.lang.String)' on a null object reference
at com.tba.mypoint_ofinterest.LocationInfo.<init>(LocationInfo.kt:11)
The two files relevant to this are:
AddLocation.kt - This is where I get the users location. Then the user presses a button: "btn_accept" and then I want it go to the LocationInfo.kt activity.
LocationInfo.kt-This is where I want to receive the location data and where the error message keeps getting thrown.
Here is the AddLocation.kt code:
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.view.View
import android.widget.Toast
import androidx.core.app.ActivityCompat
import com.google.android.gms.location.*
import kotlinx.android.synthetic.main.activity_add_location.*
class AddLocation : AppCompatActivity() {
//variables needed for location grab
lateinit var fusedLocationProviderClient: FusedLocationProviderClient
lateinit var locationRequest: LocationRequest
lateinit var locationCallback: LocationCallback
var REQUEST_CODE = 1000
lateinit var userLocation: Location
//Deal with permissions
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
REQUEST_CODE -> {
if (grantResults.size > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show()
else
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show()
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_location)
//Check for permission!
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
android.Manifest.permission.ACCESS_FINE_LOCATION
)
)
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_CODE
)
else {
buildLocationRequest()
buildLocationCallback()
//Create fused provider client
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
//get location
//start getting location
btnGetLocation.setOnClickListener(View.OnClickListener {
if (ActivityCompat.checkSelfPermission(
this,
android.Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_CODE
)
return#OnClickListener
}
fusedLocationProviderClient.requestLocationUpdates(
locationRequest, locationCallback,
Looper.myLooper()
)
//make the button invisible after clicked
btnGetLocation.visibility = View.INVISIBLE
})
}
//Listen for clicking add location then turn off GPS and proceed to next view
btn_accept.setOnClickListener {
if (ActivityCompat.checkSelfPermission(
this,
android.Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_CODE
)
}
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
locationCallback = object : LocationCallback() {
override fun onLocationResult(p0: LocationResult?) {
userLocation = p0!!.locations.get(p0!!.locations.size - 1) //get last location
}
}
var long = userLocation.longitude
var lat = userLocation.latitude
addInfo(long,lat)
}
}
private fun buildLocationCallback() {
locationCallback = object : LocationCallback() {
override fun onLocationResult(p0: LocationResult?) {
var location = p0!!.locations.get(p0!!.locations.size - 1) //get last location
userLocation = location
txtLocation.text =
location.latitude.toString() + "/" + location.longitude.toString() + "and accuracy" + location.accuracy.toString()
}
}
}
private fun buildLocationRequest() {
locationRequest = LocationRequest()
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locationRequest.interval = 5000
locationRequest.fastestInterval = 3000
locationRequest.smallestDisplacement = 10f
}
//This gives intent and takes the GPS data to the next view to be combined with user input
fun addInfo(long:Double,lat:Double) {
val infoIntent: Intent = Intent(this, LocationInfo::class.java).apply {
putExtra("LAT_DATA", lat)
putExtra("LONG_DATA",long)
}
startActivity(infoIntent)
}
//Stop getting location data if back button is pressed
override fun onSupportNavigateUp(): Boolean {
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
return super.onSupportNavigateUp()
}
}
Here is the LocationInfo.kt code:
import android.content.Intent
import android.location.Location
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import kotlinx.android.synthetic.main.activity_location_info.*
class LocationInfo : AppCompatActivity() {
val longitude = intent.getStringExtra("LONG_DATA")
val latitude = intent.getStringExtra("LAT_DATA")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_location_info)
btnSaveLocation.setOnClickListener{view ->saveInfo(view)}
textView2.text = longitude.toString()+"/"+latitude.toString()
}
fun saveInfo(x: View?){
val saveIntent: Intent = Intent(this,MainActivity::class.java)
startActivity(saveIntent)
}
}
I don't think I really understand how to use intent properly or I am mislabeling the loction data somewhere. Any advice is welcome, thank you
The issue is you are trying to access the intent even before the onCreate() is called, as a result intent is null.
Follow this,
class LocationInfo : AppCompatActivity() {
private lateinit var longitude:Double
private lateinit var latitude:Double
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_location_info)
btnSaveLocation.setOnClickListener{view ->saveInfo(view)}
longitude = intent.getDoubleExtra("LONG_DATA",0.0)
latitude = intent.getDoubleExtra("LAT_DATA",0.0)
textView2.text = longitude.toString()+"/"+latitude.toString()
}
fun saveInfo(x: View?){
val saveIntent: Intent = Intent(this,MainActivity::class.java)
startActivity(saveIntent)
}
}
You should access the Intent in the onCreate() method.
val longitude = intent.getDoubleExtra("LONG_DATA",0.0)
val latitude = intent.getDoubleExtra("LAT_DATA",0.0)

onLocationChanged() takes too much time to call

In the physical device, it takes too much time to call. But in avd it's run perfectly. I test this code in redmi note 4 and zuk z2 plus. Both device location set on HIGH_ACCURACY . I want to fetch the location rapidly. But it takes too much time to execute.
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0,0f,wcLoactionListener)
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0f,wcLoactionListener)
But if I removed this line
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0,0f,wcLoactionListener)
then onLocationChanged() not calling.
Here is my location listener
class MyListener:LocationListener {
override fun onLocationChanged(location: Location?) {
Log.d("Loc","*************************************************** "+ location)
}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
}
override fun onProviderEnabled(provider: String?) {
}
override fun onProviderDisabled(provider: String?) {
}
}
Mainactivity:-
class MainActivity : AppCompatActivity() {
val LOCATION_CODE = 212
private lateinit var locationManager: LocationManager
private lateinit var cwcLoactionListener:MyListener
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
cwcLoactionListener = MyListener()
checkLocationPermission()
}
#SuppressLint("MissingPermission")
fun fechLOc(){
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0,0f,cwcLoactionListener)
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,500,0f,cwcLoactionListener)
}
private fun checkLocationPermission() {
if(Build.VERSION.SDK_INT>=23){
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED ){
requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_CODE)
return
}
}
fechLOc()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
LOCATION_CODE->{
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this,"Accept this permission", Toast.LENGTH_LONG).show()
}else{
fechLOc()
}
}
else ->{
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
}
}
manifest
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Get location android Kotlin

I recently added get location function. When I try to show longitude and latitude, it returns zero.
This my LocationListener class:
inner class MylocationListener: LocationListener {
constructor():super(){
mylocation= Location("me")
mylocation!!.longitude
mylocation!!.latitude
}
override fun onLocationChanged(location: Location?) {
mylocation=location
}
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {}
override fun onProviderEnabled(p0: String?) {}
override fun onProviderDisabled(p0: String?) {}
}
And this my GetUserLocation function:
fun GetUserLocation(){
var mylocation= MylocationListener()
var locationManager=getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0.1f,mylocation)
}
And this my function to return my longitude and latitude:
fun getLoction (view: View){
prgDialog!!.show();
GetUserLocation()
button.setTextColor(getResources().getColor(R.color.green));
textView.text = mylocation!!.latitude.toFloat().toString()
Toast.makeText(this, mylocation!!.latitude.toFloat().toString(), Toast.LENGTH_LONG).show()
Toast.makeText(this, mylocation!!.longitude.toFloat().toString(), Toast.LENGTH_LONG).show()
prgDialog!!.hide()
}
In 2019 Best Offical Solution in Kotlin
Google API Client/FusedLocationApi are deprecated and Location Manager is not useful at all.
So Google prefer Fused Location Provider Using the Google Play services location APIs
"FusedLocationProviderClient" is used to get location and its better way for battery saving and accuracy
Here is sample code in kotlin to get the last known location /one-time location( equivalent to the current location)
// declare a global variable of FusedLocationProviderClient
private lateinit var fusedLocationClient: FusedLocationProviderClient
// in onCreate() initialize FusedLocationProviderClient
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
/**
* call this method for receive location
* get location and give callback when successfully retrieve
* function itself check location permission before access related methods
*
*/
fun getLastKnownLocation() {
fusedLocationClient.lastLocation
.addOnSuccessListener { location->
if (location != null) {
// use your location object
// get latitude , longitude and other info from this
}
}
}
If your app can continuously track the location then you have to receive Receive location updates
Check the sample for that in kotlin
// declare a global variable FusedLocationProviderClient
private lateinit var fusedLocationClient: FusedLocationProviderClient
// in onCreate() initialize FusedLocationProviderClient
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
// globally declare LocationRequest
private lateinit var locationRequest: LocationRequest
// globally declare LocationCallback
private lateinit var locationCallback: LocationCallback
/**
* call this method in onCreate
* onLocationResult call when location is changed
*/
private fun getLocationUpdates()
{
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
locationRequest = LocationRequest()
locationRequest.interval = 50000
locationRequest.fastestInterval = 50000
locationRequest.smallestDisplacement = 170f // 170 m = 0.1 mile
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY //set according to your app function
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
if (locationResult.locations.isNotEmpty()) {
// get latest location
val location =
locationResult.lastLocation
// use your location object
// get latitude , longitude and other info from this
}
}
}
}
//start location updates
private fun startLocationUpdates() {
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
null /* Looper */
)
}
// stop location updates
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
// stop receiving location update when activity not visible/foreground
override fun onPause() {
super.onPause()
stopLocationUpdates()
}
// start receiving location update when activity visible/foreground
override fun onResume() {
super.onResume()
startLocationUpdates()
}
Make sure you take care about Mainfaist permission and runtime permission for location
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
and for Gradle add this
implementation 'com.google.android.gms:play-services-location:17.0.0'
For more details follow these official documents
https://developer.android.com/training/location/retrieve-current
https://developer.android.com/training/location/receive-location-updates
https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient
When GetUserLocation returns, locationManager goes out of scope and presumably is destroyed, preventing onLocationChanged from being called and providing updates.
Also, you've defined mylocation inside of GetUserLocation so it also goes out of scope and further kills any chance or your getting an update.
You have not shown where and how the outer mylocation is declared (outside of GetUserLocation), but how ever it is declared, it is being shadowed by the one inside of GetUserLocation. So you aren't getting much.
Here is an example of how you might do it. (The variable thetext is defined within the layout xml and accessed with Kotlin extensions.)
// in the android manifest
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
// allow these through Appliation Manager if necessary
// inside a basic activity
private var locationManager : LocationManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
// Create persistent LocationManager reference
locationManager = getSystemService(LOCATION_SERVICE) as LocationManager?
fab.setOnClickListener { view ->
try {
// Request location updates
locationManager?.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0L, 0f, locationListener)
} catch(ex: SecurityException) {
Log.d("myTag", "Security Exception, no location available")
}
}
}
//define the listener
private val locationListener: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
thetext.text = ("" + location.longitude + ":" + location.latitude)
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
override fun onProviderEnabled(provider: String) {}
override fun onProviderDisabled(provider: String) {}
}
I know it's late, but now Google has made it simpler to use. In the developer site, it says that you need to create a Client:
private lateinit var fusedLocationClient: FusedLocationProviderClient
Then onCreate get the provider:
override fun onCreate(savedInstanceState: Bundle?) {
// ...
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
}
And finally, to get your last location just call:
//Don't forget to ask for permissions for ACCESS_COARSE_LOCATION
//and ACCESS_FINE_LOCATION
#SuppressLint("MissingPermission")
private fun obtieneLocalizacion(){
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
latitude = location?.latitude
longitude = location?.longitude
}
}
*Tested with this implementation for location (Setup in your app gradle file)
implementation 'com.google.android.gms:play-services-location:15.0.1'
For more info, check this link:
Obtain last location
Get location with address in android kotlin
Add this line in dependencies
implementation 'com.google.android.gms:play-services-location:17.0.0'
Add this in AndroidManifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Copy this below code in your class
class MainActivity : AppCompatActivity() {
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
/*Check location*/
checkLocation()
}
private fun checkLocation(){
val manager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
showAlertLocation()
}
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
getLocationUpdates()
}
private fun showAlertLocation() {
val dialog = AlertDialog.Builder(this)
dialog.setMessage("Your location settings is set to Off, Please enable location to use this application")
dialog.setPositiveButton("Settings") { _, _ ->
val myIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(myIntent)
}
dialog.setNegativeButton("Cancel") { _, _ ->
finish()
}
dialog.setCancelable(false)
dialog.show()
}
private fun getLocationUpdates() {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
locationRequest = LocationRequest()
locationRequest.interval = 50000
locationRequest.fastestInterval = 50000
locationRequest.smallestDisplacement = 170f //170 m = 0.1 mile
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY //according to your app
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
if (locationResult.locations.isNotEmpty()) {
/*val location = locationResult.lastLocation
Log.e("location", location.toString())*/
val addresses: List<Address>?
val geoCoder = Geocoder(applicationContext, Locale.getDefault())
addresses = geoCoder.getFromLocation(
locationResult.lastLocation.latitude,
locationResult.lastLocation.longitude,
1
)
if (addresses != null && addresses.isNotEmpty()) {
val address: String = addresses[0].getAddressLine(0)
val city: String = addresses[0].locality
val state: String = addresses[0].adminArea
val country: String = addresses[0].countryName
val postalCode: String = addresses[0].postalCode
val knownName: String = addresses[0].featureName
Log.e("location", "$address $city $state $postalCode $country $knownName")
}
}
}
}
}
// Start location updates
private fun startLocationUpdates() {
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
null /* Looper */
)
}
// Stop location updates
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
// Stop receiving location update when activity not visible/foreground
override fun onPause() {
super.onPause()
stopLocationUpdates()
}
// Start receiving location update when activity visible/foreground
override fun onResume() {
super.onResume()
startLocationUpdates()
}}
Run your code and check the log, Happy Coding
I read many of answers but question is get only last known location.
With receiver it continuously send latitude and longitude
I have solution for this in kotlin..
Give permissions
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
public fun getLastKnownLocation(context: Context) {
val locationManager: LocationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val providers: List<String> = locationManager.getProviders(true)
var location: Location? = null
for (i in providers.size - 1 downTo 0) {
location= locationManager.getLastKnownLocation(providers[i])
if (location != null)
break
}
val gps = DoubleArray(2)
if (location != null) {
gps[0] = location.getLatitude()
gps[1] = location.getLongitude()
Log.e("gpsLat",gps[0].toString())
Log.e("gpsLong",gps[1].toString())
}
}
I would like to help someone who is trying to get location from scratch.
Here is the reference: Kotlin Get Current Location
Code will first check whether location is on or off in device and then will fetch latitude and longitudes and will update it constantly.
In build.gradle(Module:app) file put this
compile 'com.google.android.gms:play-services:11.8.0'
activity_main.xml code
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/latitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Latitude:"
android:textSize="18sp" />
<TextView
android:id="#+id/latitude_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/latitude"
android:layout_marginLeft="10dp"
android:layout_toRightOf="#+id/latitude"
android:textSize="16sp" />
<TextView
android:id="#+id/longitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Longitude:"
android:layout_marginTop="24dp"
android:textSize="18sp" />
<TextView
android:id="#+id/longitude_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/longitude"
android:layout_marginLeft="10dp"
android:layout_toRightOf="#+id/longitude"
android:textSize="16sp"/>
</RelativeLayout>
MainActivity.kt
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.provider.Settings
import android.support.v4.app.ActivityCompat
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import android.widget.Toast
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.api.GoogleApiClient
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.model.LatLng
class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener {
private var mLatitudeTextView: TextView? = null
private var mLongitudeTextView: TextView? = null
private var mGoogleApiClient: GoogleApiClient? = null
private var mLocation: Location? = null
private var mLocationManager: LocationManager? = null
private var mLocationRequest: LocationRequest? = null
private val listener: com.google.android.gms.location.LocationListener? = null
private val UPDATE_INTERVAL = (2 * 1000).toLong() /* 10 secs */
private val FASTEST_INTERVAL: Long = 2000 /* 2 sec */
private var locationManager: LocationManager? = null
private val isLocationEnabled: Boolean
get() {
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
return locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager!!.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mLatitudeTextView = findViewById(R.id.latitude_textview) as TextView
mLongitudeTextView = findViewById(R.id.longitude_textview) as TextView
mGoogleApiClient = GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build()
mLocationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
Log.d("gggg","uooo");
checkLocation() //check whether location service is enable or not in your phone
}
#SuppressLint("MissingPermission")
override fun onConnected(p0: Bundle?) {
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
}
startLocationUpdates()
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient)
if (mLocation == null) {
startLocationUpdates()
}
if (mLocation != null) {
// mLatitudeTextView.setText(String.valueOf(mLocation.getLatitude()));
//mLongitudeTextView.setText(String.valueOf(mLocation.getLongitude()));
} else {
Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show()
}
}
override fun onConnectionSuspended(i: Int) {
Log.i(TAG, "Connection Suspended")
mGoogleApiClient!!.connect()
}
override fun onConnectionFailed(connectionResult: ConnectionResult) {
Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode())
}
override fun onStart() {
super.onStart()
if (mGoogleApiClient != null) {
mGoogleApiClient!!.connect()
}
}
override fun onStop() {
super.onStop()
if (mGoogleApiClient!!.isConnected()) {
mGoogleApiClient!!.disconnect()
}
}
#SuppressLint("MissingPermission")
protected fun startLocationUpdates() {
// Create the location request
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL)
// Request location updates
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
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this)
Log.d("reque", "--->>>>")
}
override fun onLocationChanged(location: Location) {
val msg = "Updated Location: " +
java.lang.Double.toString(location.latitude) + "," +
java.lang.Double.toString(location.longitude)
mLatitudeTextView!!.text = location.latitude.toString()
mLongitudeTextView!!.text = location.longitude.toString()
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
// You can now create a LatLng Object for use with maps
val latLng = LatLng(location.latitude, location.longitude)
}
private fun checkLocation(): Boolean {
if (!isLocationEnabled)
showAlert()
return isLocationEnabled
}
private fun showAlert() {
val dialog = AlertDialog.Builder(this)
dialog.setTitle("Enable Location")
.setMessage("Your Locations Settings is set to 'Off'.\nPlease Enable Location to " + "use this app")
.setPositiveButton("Location Settings") { paramDialogInterface, paramInt ->
val myIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(myIntent)
}
.setNegativeButton("Cancel") { paramDialogInterface, paramInt -> }
dialog.show()
}
companion object {
private val TAG = "MainActivity"
}
}
gradle(Module: appname.app)
buildFeatures{
viewBinding true
} // for databinding
dependencies{
implementation 'com.google.android.gms:play-services-location:18.0.0'
}
manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
activity:
class Updateposition : AppCompatActivity() {
private lateinit var bind: ActivityUpdatepositionBinding
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
//private lateinit var lat: String // :Double
//private lateinit var long: String // ||.toDouble
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bind = ActivityUpdatepositionBinding.inflate(layoutInflater)
setContentView(bind.root)
//supportActionBar!!.hide()
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
try {
getActualLocation()
//getActualLocation()
//getActualLocation()
}catch (e: java.lang.Exception){
e.printStackTrace()
}
}
private fun getActualLocation() {
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){
bind.tvLatitude.text = "${it.latitude}" // it.longitude is a Double
bind.tvLongitude.text = "${it.longitude}" // tvLongitude is a TextView
}
}
}// one curly brace could be missing (or not)
run it then close your app then run again and voila!

Categories

Resources