This code belongs to a fragment which shows the user's current location.After getting location when I want to go back to previous fragment App crashes.Logcat says error is happening here : "val geocoder = Geocoder(requireContext(), Locale.getDefault())" If anyone could assist me, I would greatly appreciate it
class LocationFragment : DialogFragment(), OnMapReadyCallback {
lateinit var binding: FragmentLocationBinding
private lateinit var map: GoogleMap
private val REQUEST_LOCATION_PERMISSION = 1
var lat: Double = 0.0
var long: Double = 0.0
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentLocationBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(requireContext())
enableMyLocation()
binding.apply {
prgBar.visibility=View.VISIBLE
btnSaveLocation.setOnClickListener {
dismiss()
}
val mapFragment = childFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this@LocationFragment)
}
}
override fun onStart() {
super.onStart()
val dialog: Dialog? = dialog
if (dialog != null) {
dialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
//dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
}
override fun onMapReady(p0: GoogleMap) {
map = p0
}
private fun isPermissionGranted(): Boolean {
return ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
@SuppressLint("VisibleForTests")
private fun checkDeviceLocationSettings(resolve: Boolean = true) {
val locationRequest = LocationRequest.create().apply {
priority = LocationRequest.PRIORITY_LOW_POWER
}
val requestBuilder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
val settingsClient = LocationServices.getSettingsClient(requireActivity())
val locationSettingsResponseTask =
settingsClient.checkLocationSettings(requestBuilder.build())
locationSettingsResponseTask.addOnFailureListener { exception ->
if (exception is ResolvableApiException && resolve) {
try {
exception.startResolutionForResult(
requireActivity(),
REQUEST_TURN_DEVICE_LOCATION_ON
)
} catch (sendEx: IntentSender.SendIntentException) {
Log.d(TAG, "Error getting location settings resolution: " sendEx.message)
}
} else {
Snackbar.make(
binding.root,
R.string.location_required_error, Snackbar.LENGTH_INDEFINITE
).setAction(android.R.string.ok) {
checkDeviceLocationSettings()
}.show()
}
}
}
@TargetApi(Build.VERSION_CODES.Q)
private fun requestQPermission() {
val hasForegroundPermission = ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
if (hasForegroundPermission) {
val hasBackgroundPermission = ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_BACKGROUND_LOCATION
) == PackageManager.PERMISSION_GRANTED
if (hasBackgroundPermission) {
checkDeviceLocationSettings()
} else {
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
REQUEST_CODE_BACKGROUND
)
}
}
}
private fun enableMyLocation() {
if (isPermissionGranted()) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
checkDeviceLocationSettings()
} else {
requestQPermission()
}
updateLocation()
} else {
ActivityCompat.requestPermissions(
context as Activity,
arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
}
}
private fun updateLocation() {
if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
) {
return
}
fusedLocationProviderClient.requestLocationUpdates(
locationRequest(), locationCallback,
Looper.myLooper()
)
}
private fun locationRequest(): LocationRequest {
return LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 3000)
.setWaitForAccurateLocation(false)
.setMinUpdateIntervalMillis(5000)
.setMaxUpdateDelayMillis(5000)
.build()
}
private var locationCallback = object : LocationCallback() {
override fun onLocationResult(p0: LocationResult) {
val location: Location? = p0.lastLocation
if (location != null) {
updateAddressUI(location)
}
}
}
@SuppressLint("MissingPermission")
fun updateAddressUI(location: Location) {
map.isMyLocationEnabled = true
val addressList: ArrayList<Address>
val geocoder = Geocoder(requireContext(), Locale.getDefault()) //Getting error here
addressList = geocoder.getFromLocation(
location.latitude,
location.longitude,
1
) as ArrayList<Address>
lat = addressList[0].latitude
long = addressList[0].longitude
binding.prgBar.visibility=View.INVISIBLE
Toast.makeText(requireContext(), "$lat \n $long", Toast.LENGTH_SHORT).show()
val latLng = LatLng(lat, long)
val markerOptions = MarkerOptions().position(latLng).title("I am here!")
map.animateCamera(CameraUpdateFactory.newLatLng(latLng))
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
map.addMarker(markerOptions)?.setIcon(bitmapFromVector(requireContext(),R.drawable.baseline_emoji_people_24))
}
private fun bitmapFromVector(context: Context, vectorResId: Int): BitmapDescriptor? {
val vectorDrawable = ContextCompat.getDrawable(context, vectorResId)
vectorDrawable!!.setBounds(0, 0, vectorDrawable.intrinsicWidth, vectorDrawable.intrinsicHeight)
val bitmap = Bitmap.createBitmap(vectorDrawable.intrinsicWidth, vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
vectorDrawable.draw(canvas)
return BitmapDescriptorFactory.fromBitmap(bitmap)
}
override fun onResume() {
super.onResume()
enableMyLocation()
}
}
I used 'requireActivity' instead of 'requireContext' but didn't work
CodePudding user response:
As you said, beacuse the crash happens when you go back to the previous fragment, probably the locationCallback getting called when the current fragment is detached from the activity. Inside the updateAddressUI you are getting the context in that momment when your view is detached.
If is ok with your logic you can keep the context reference inside the callBack object and work with this.
Try to change the locationCallback to and pass the context to the updateAddressUI function.
private var locationCallback = object : LocationCallback() {
val context = requireContext()
override fun onLocationResult(p0: LocationResult) {
val location: Location? = p0.lastLocation
if (location != null) {
updateAddressUI(location, context)
}
}
}
Change also the updateAddressUI function like this.
@SuppressLint("MissingPermission")
fun updateAddressUI(location: Location, context: Context) {
map.isMyLocationEnabled = true
val addressList: ArrayList<Address>
val geocoder = Geocoder(context, Locale.getDefault()) //Getting error here
addressList = geocoder.getFromLocation(
location.latitude,
location.longitude,
1
) as ArrayList<Address>
lat = addressList[0].latitude
long = addressList[0].longitude
binding.prgBar.visibility=View.INVISIBLE
Toast.makeText(context, "$lat \n $long", Toast.LENGTH_SHORT).show()
val latLng = LatLng(lat, long)
val markerOptions = MarkerOptions().position(latLng).title("I am here!")
map.animateCamera(CameraUpdateFactory.newLatLng(latLng))
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
map.addMarker(markerOptions)?.setIcon(bitmapFromVector(context,R.drawable.baseline_emoji_people_24))
}
CodePudding user response:
I changed the code in this way :
val geocoder = context?.let { Geocoder(it, Locale.getDefault()) }
in this methode :
fun updateAddressUI(location: Location) {
map.isMyLocationEnabled = true
val addressList: ArrayList<Address>
val geocoder = context?.let { Geocoder(it, Locale.getDefault()) }
if (geocoder != null) {
addressList = geocoder.getFromLocation(
location.latitude,
location.longitude,
1
) as ArrayList<Address>
lat = addressList[0].latitude
long = addressList[0].longitude
}