androidkotlingoogle-geocoder

I get "not attached to a context" error when I want to go back from current fragment


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


Solution

  • 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
            }