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...)
}
}
}
Related
I am trying to request a user's location. The first time I request a user's location, it works as intended, with a permission rationale dialog that pops up and then the user is given a choice between fine and coarse location permission. However, if the user rejects the location permission, and then clicks on the find location button, I want the dialog to pop up again, however nothing happens. It seems like the OS is storing the user's choice, and not allowing for another attempt at finding the location. How do I fix this? Below is the relevant code.
package com.example.groupupandroid
import android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.content.pm.PackageManager
import android.location.Location
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.iterator
import androidx.core.view.size
import androidx.fragment.app.Fragment
import com.example.groupupandroid.databinding.FragmentHomeScreenBinding
import com.example.groupupandroid.databinding.NavHeaderBinding
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.gms.tasks.OnSuccessListener
import com.google.android.material.navigation.NavigationView
import com.google.android.material.navigation.NavigationView.*
import java.util.jar.Manifest
class HomeScreenFragment : Fragment(), GoogleMap.OnMapLongClickListener,
GoogleMap.OnMarkerDragListener, GoogleMap.OnMyLocationButtonClickListener,
GoogleMap.OnMyLocationClickListener, OnNavigationItemSelectedListener{
private val callback = OnMapReadyCallback { googleMap ->
mMap = googleMap
mMap.mapType = GoogleMap.MAP_TYPE_NORMAL
mMap.uiSettings.isMyLocationButtonEnabled = false;
enableUserLocation()
}
private var requestLocationPermissions = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
permissions.forEach { actionMap ->
when (actionMap.key) {
android.Manifest.permission.ACCESS_COARSE_LOCATION -> {
if (actionMap.value) {
// permission granted continue the normal
// workflow of app
Log.i("DEBUG", "permission granted")
mMap.isMyLocationEnabled = true
zoomToUserLocation()
} else {
// if permission denied then check whether never
// ask again is selected or not by making use of
// !ActivityCompat.shouldShowRequest
// PermissionRationale(requireActivity(),
// Manifest.permission.CAMERA)
Log.i("DEBUG", "permission denied")
}
}
android.Manifest.permission.ACCESS_FINE_LOCATION -> {
if (actionMap.value) {
// permission granted continue the normal
// workflow of app
Log.i("DEBUG", "permission granted")
mMap.isMyLocationEnabled = true
zoomToUserLocation()
} else {
// if permission denied then check whether never
// ask again is selected or not by making use of
// !ActivityCompat.shouldShowRequest
// PermissionRationale(requireActivity(),
// Manifest.permission.CAMERA)
Log.i("DEBUG", "permission denied")
}
}
}
}
}
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var mMap: GoogleMap
private lateinit var mContext: Context
// private lateinit var mActivity: Activity
// Getting xml objects
private var binding: FragmentHomeScreenBinding? = null
private var headerBinding: NavHeaderBinding? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentHomeScreenBinding.inflate(layoutInflater)
headerBinding = NavHeaderBinding.inflate(layoutInflater)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(mContext)
// Inflate the layout for this fragment
return binding?.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
mapFragment?.getMapAsync(callback)
binding?.menuButton?.setOnClickListener {
binding?.drawerLayout?.open()
}
binding?.navView?.setNavigationItemSelectedListener { menuItem ->
when (menuItem.itemId) {
R.id.HomeMenuItem -> {
// menuItem.isChecked = true
binding?.navView?.setCheckedItem(menuItem)
binding?.drawerLayout?.close()
}
R.id.ProfileMenuItem -> {
// menuItem.isChecked = true
binding?.navView?.setCheckedItem(menuItem)
binding?.drawerLayout?.close()
}
R.id.MyGroupsMenuItem -> {
// menuItem.isChecked = true
binding?.navView?.setCheckedItem(menuItem)
binding?.drawerLayout?.close()
}
R.id.SignOutMenuItem -> {
// menuItem.isChecked = true
binding?.navView?.setCheckedItem(menuItem)
binding?.drawerLayout?.close()
}
}
// Handle menu item selected
true
}
binding?.locationButton?.setOnClickListener {
enableUserLocation()
}
}
private fun enableUserLocation() {
// 1. Check if permissions are granted, if so, enable the my location layer
if (ContextCompat.checkSelfPermission(mContext,
android.Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(mContext,
android.Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED) {
mMap.isMyLocationEnabled = true
zoomToUserLocation()
return
}
// 2. If a permission rationale dialog should be shown
if (ActivityCompat.shouldShowRequestPermissionRationale((activity as MainActivity),
android.Manifest.permission.ACCESS_FINE_LOCATION
) || ActivityCompat.shouldShowRequestPermissionRationale((activity as MainActivity),
android.Manifest.permission.ACCESS_COARSE_LOCATION
)
) {
val builder: AlertDialog.Builder = AlertDialog.Builder(mContext)
builder.setTitle(R.string.rationale_title)
.setMessage(R.string.rationale_desc)
.setPositiveButton("Ok") { _, _ ->
requestLocationPermissions.launch(locationPermissions)
}
builder.create().show()
return
}
// 3. Otherwise, request permission
requestLocationPermissions.launch(locationPermissions)
}
private fun zoomToUserLocation() {
fusedLocationClient.lastLocation
.addOnSuccessListener { location : Location? ->
// Got last known location. In some rare situations this can be null.
if (location!=null){
val userLocationLatLng = LatLng(location.latitude, location.longitude)
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(userLocationLatLng, 13.0F))
}
}
}
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context
}
override fun onMapLongClick(p0: LatLng) {
TODO("Not yet implemented")
}
override fun onMarkerDrag(p0: Marker) {
TODO("Not yet implemented")
}
override fun onMarkerDragEnd(p0: Marker) {
TODO("Not yet implemented")
}
override fun onMarkerDragStart(p0: Marker) {
TODO("Not yet implemented")
}
override fun onMyLocationButtonClick(): Boolean {
TODO("Not yet implemented")
}
override fun onMyLocationClick(p0: Location) {
TODO("Not yet implemented")
}
private fun presentLocationNecessaryDialogue() {
val builder: AlertDialog.Builder = AlertDialog.Builder(mContext)
builder.setTitle(R.string.rationale_title)
.setMessage(R.string.rationale_desc)
.setPositiveButton("Ok") { _, _ ->
requestLocationPermissions.launch(locationPermissions)
}
builder.create().show()
}
companion object {
/**
* Request code for location permission request.
*
* #see .onRequestPermissionsResult
*/
private val locationPermissions = arrayOf(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION
)}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
TODO("Not yet implemented")
}
}
Thank you in advance for your help.
I have a simple app that, as of right now, contains main_activity.kt and fragment_results.kt and their xml files. The premise of the app is that the user scans a barcode and then hits a button. A fragment comes up and displays all of the data tied to that barcode. Once I understand how to do this part, I will extend it so the user can add barcodes to the spreadsheet but that's down the road.
The problem I'm running into with Kotlin is that it looks like a lot of stuff is deprecated and while android studio is great at showing me the new ways to do things, a simple to follow tutorial is hard to find.
main_activity.kt
package com.example.barcode
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentTransaction
import com.budiyev.android.codescanner.AutoFocusMode
import com.budiyev.android.codescanner.CodeScanner
import com.budiyev.android.codescanner.DecodeCallback
import com.budiyev.android.codescanner.ErrorCallback
import com.budiyev.android.codescanner.ScanMode
import com.example.barcode.databinding.ActivityMainBinding
private const val CAMERA_REQUEST_CODE = 101
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var codeScanner: CodeScanner
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setupPermissions()
codeScanner()
}
private fun codeScanner() {
codeScanner = CodeScanner(this, binding.scannerView)
codeScanner.apply {codeScanner
camera = CodeScanner.CAMERA_BACK
formats = CodeScanner.ALL_FORMATS
autoFocusMode = AutoFocusMode.SAFE
scanMode = ScanMode.SINGLE
isAutoFocusEnabled = true
isFlashEnabled = false
decodeCallback = DecodeCallback {
binding.button.text = getString(R.string.searchButtonLabel, it.text)
}
errorCallback = ErrorCallback {
Log.e("Main", "Camera Initilization failed ${it.message}")
}
}
binding.scannerView.setOnClickListener {
codeScanner.startPreview()
binding.button.text = getString(R.string.resetButtonLabel)
}
}
override fun onResume() {
super.onResume()
codeScanner.startPreview()
}
override fun onPause() {
codeScanner.releaseResources()
super.onPause()
}
private fun setupPermissions() {
val permission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
if (permission != PackageManager.PERMISSION_GRANTED) {
makeRequest()
}
}
private fun makeRequest(){
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.CAMERA),
CAMERA_REQUEST_CODE)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
when (requestCode) {
CAMERA_REQUEST_CODE -> {
if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED){
Toast.makeText(this,"You need the camera for this app", Toast.LENGTH_SHORT).show()
}else{
}
}
}
}
}
My resultsFragment.kt is a stock blank .kt. Haven't worked on that programming yet.
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)
I hope you are doing good in your field.
Need some help for getting list of postal codes from the user visible area of google map for that i got the visible region. reference link for getting visible region
Now i am trying to get the address using Geocoder and visible region value but i get the exception.
Here i will show my code.[ Worked in Kotlin]
MainActivity.kt
import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.location.Geocoder
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.app.AppCompatActivity
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
class MapActivity : AppCompatActivity(), OnMapReadyCallback {
var map: SupportMapFragment? = null
var googleMap: GoogleMap? = null
var MY_LOCATION_REQUEST_CODE: Int = 201
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map)
}
override fun onResume() {
super.onResume()
if (map == null) {
map = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
map!!.getMapAsync(this)
}
}
override fun onMapReady(googleMap: GoogleMap?) {
this.googleMap = googleMap
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
googleMap!!.isMyLocationEnabled = true
this.googleMap!!.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(37.422, -122.084), 14.0f))
getAddressListfromVisibleRegion()
} else {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), MY_LOCATION_REQUEST_CODE)
}
}
private fun getAddressListfromVisibleRegion() {
var vregion = googleMap!!.projection.visibleRegion.latLngBounds
var addressList = Geocoder(this).getFromLocationName("", 100,
vregion.southwest.latitude, vregion.southwest.longitude,
vregion.northeast.latitude, vregion.northeast.longitude)
/*
val ne = vregion.northeast // LatLng of the north-east corner
val sw = vregion.southwest // LatLng of the south-west corner
val nw = LatLng(ne.latitude, sw.longitude)
val se = LatLng(sw.latitude, ne.longitude)
var addressList1 = Geocoder(this).getFromLocationName("", 100,
nw.latitude, nw.longitude, se.latitude, se.longitude)
*/
}
#SuppressLint("MissingPermission")
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (requestCode == MY_LOCATION_REQUEST_CODE) {
if (permissions.size == 1 &&
permissions[0] == Manifest.permission.ACCESS_FINE_LOCATION &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
googleMap!!.isMyLocationEnabled = true
this.googleMap!!.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(37.422, -122.084), 14.0f))
}
}
}
}
Got the exception when implement Geocoder
I was refered this link for above issue and also checked with real device but still face same issue when execute Geocoder statement.
Anyone want to share knowledge with me that will be good help for me
Thanks in advance.
I want to get current location when I touch a button.
Touch a button
requestLocationUpdates one time, and get current location, then removeLocationUpdates.
The problem is in 2. I don't want GPS and wifi work all time when I requestLocationUpdates. But I don't know how to removeLocationUpdates in
locationCallback.
package com.example.location
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.util.Log
import android.widget.Button
import android.widget.TextView
import com.google.android.gms.location.*
class MainActivity : AppCompatActivity() {
private var userAgreePermissionCode = 1
private lateinit var userLocationClient: FusedLocationProviderClient
private lateinit var userLocationCallback: LocationCallback
#SuppressLint("RestrictedApi")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val somePermission = arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION)
for (p in somePermission ){
if(ActivityCompat.checkSelfPermission(this, p) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(this, somePermission , userAgreePermissionCode)
break
}
findViewById<Button>(R.id.Locate).setOnClickListener{
userLocationClient = LocationServices.getFusedLocationProviderClient(this)
val userLocationRequest = LocationRequest().apply {
interval = 1000
fastestInterval = 1000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
// Problem is here
userLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
for (location in locationResult.locations){
// I want to get the first update location(current location) and close requestLocationUpdates!!!!
// Only one time, not keep update
Log.i("longitude", location.longitude.toString())
Log.i("latitude", location.latitude.toString())
// findViewById<TextView>(R.id.Longitude).text = location.longitude.toString()
// findViewById<TextView>(R.id.Latitude).text = location.latitude.toString()
// Problem here, it's error.
userLocationClient.removeLocationUpdates(userLocationCallback)
}
}
}
userLocationClient.requestLocationUpdates(userLocationRequest,userLocationCallback,null)
}
}
// -----------------------------------------
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
userAgreePermissionCode -> {
for( i in 0..(grantResults.size-1) ){
if ((grantResults.isNotEmpty() && grantResults[i] == PackageManager.PERMISSION_GRANTED))
Log.i("Status:", "Agree a permission")
else
finish()
}
return
}
}
}
// -----------------------------------------
}
After requesting you will get callback
You are calling userLocationClient.removeLocationUpdates(userLocationCallback)
in loop. need to call after break outside loop after getting location object
https://developer.android.com/training/location/receive-location-updates.html#stop-updates
To use removeLocationUpdates from within an anonymous LocationListener object, you can do removeLocationUpdates(this).