Search code examples
androidkotlinillegalstateexceptionmapfragment

java.lang.IllegalStateException: Fragment MapFragment{2fe7116} (69b05d78-5cf3-46a9-829c-6b6507944575) not attached to an activity.?


I am developing location based android app using google maps but when I run project I am getting crash and getting following exception java.lang.IllegalStateException: Fragment MapFragment{2fe7116} (69b05d78-5cf3-46a9-829c-6b6507944575) not attached to an activity. at androidx.fragment.app.Fragment.requireActivity(Fragment.java:995)

I am getting exception in following function in my MapFragment

@SuppressLint("MissingPermission")
private fun getDeviceLocation() {
    /*
     * Get the best and most recent location of the device, which may be null in rare
     * cases when a location is not available.
     */
    try {
        if (locationPermissionGranted) {
            val locationResult = fusedLocationProviderClient.lastLocation
            locationResult.addOnCompleteListener(requireActivity()) { task ->
                if (task.isSuccessful) {
                    // Set the map's camera position to the current location of the device.
                    lastKnownLocation = task.result
                    if (lastKnownLocation != null) {
                        map.moveCamera(
                            CameraUpdateFactory.newLatLngZoom(
                                LatLng(
                                    lastKnownLocation!!.latitude,
                                    lastKnownLocation!!.longitude
                                ), DEFAULT_ZOOM.toFloat()
                            )
                        )
                    } else {
                        gotoDefaultLocation()
                    }
                } else {
                    Log.d(TAG, "Current location is null. Using defaults.")
                    Log.e(TAG, "Exception: %s", task.exception)
                    gotoDefaultLocation()
                }
            }
        }
    } catch (e: SecurityException) {
        MakeToast("Standort Zugriff leider nicht erlaubt")
        Log.e("Exception: %s", e.message, e)
    }
}

I have followed all stackoverflow answer it did not solve my problem

I have tried following stackoverflow answer as well java.lang.IllegalStateException: Fragment not attached to Activity I want to know where exactly I am making mistake

below My Full MapFragment.kt

@AndroidEntryPoint
class MapFragment : Fragment(), OnMapReadyCallback, GoogleMap.OnMarkerClickListener,
    GoogleMap.OnInfoWindowClickListener {

    private val binding by lazy { MapFragmentBinding.inflate(layoutInflater) }

    private var locationPermissionGranted: Boolean = false



    //    private var mMap: MapView? = null
    private lateinit var map: GoogleMap
    private val cafMarker: MutableList<CafMarker> = mutableListOf()
    private val viewModel by viewModels<MapViewModel>()

    @Inject
    lateinit var sharedPref: SharedPref

    // Declare a variable for the cluster manager.
    private lateinit var clusterManager: ClusterManager<CafMarker>
    private val markerAdapter by lazy { MarkerAdapter() }
    private lateinit var dialogMarker: Dialog

    private var isRegistered: Boolean = false

    // The entry point to the Places API.
    private lateinit var placesClient: PlacesClient
    private var lastKnownLocation: Location? = null
    private var cameraPosition: CameraPosition? = null

    // The entry point to the Fused Location Provider.
    private lateinit var fusedLocationProviderClient: FusedLocationProviderClient

    private val defaultLocation = LatLng(51.1633611, 10.4476833)

    lateinit var CurrentChargePoint: ChargePoint
    lateinit var cp: ChargePoint
    private var ChargePoints: MutableList<ChargePoint> = mutableListOf<ChargePoint>()
    private val TAG = "MapFragment"

    private lateinit var activityContext: Context



    companion object {
        fun newInstance() = MapFragment()
        val REQUEST_CODE_LOCATION = 32
        private const val COUNTRY_ZOOM = 5.85
        private const val DEFAULT_ZOOM = 15
        private const val PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1

        private const val KEY_CAMERA_POSITION = "camera_position"
        private const val KEY_LOCATION = "location"
        private const val M_MAX_ENTRIES = 5
    }


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        Log.d("setNavigationToken", "setNavigation: ${sharedPref.token}")
        activityContext = requireContext()
        binding.mapView.onCreate(savedInstanceState)

        binding.mapView.getMapAsync(this)

        binding.mapView.setOnClickListener(clickListener)

        binding.gotoBookingButton.setOnClickListener(clickListener);
        binding.StationInfo.isVisible = false;
        createChannel("caf", "alarm")



        if (savedInstanceState != null) {
            lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION)
            cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION)
        }

        binding.qrButton.setOnClickListener(clickListener)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewModel.map(sharedPref.token)

        Log.d("onViewCreatedToken", "onViewCreated: ${sharedPref.token}")


    }

    val clickListener = View.OnClickListener { view ->

        when (view.getId()) {
//            R.id.gotoBookingButton -> {
//                appCommon.CurrentChargePoint = CurrentChargePoint
//                if (sharedPref.token.length > 0) {
//                    Log.d("@@@@@@@", ": $sharedPref")
////                    appCommon.isAdhocBooking = false
//                    findNavController().navigate(R.id.navigation_reserve)
//                } else {
//                    findNavController().navigate(R.id.navigation_settings_login)
//                }
//            }
            R.id.mapView -> {
                binding.StationInfo.isVisible = false
            }
            R.id.qrButton -> {
                findNavController().navigate(R.id.activity_qr)
            }
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)

        binding.mapView.onSaveInstanceState(outState)
    }

    @SuppressLint("MissingPermission")
    override fun onMapReady(googleMap: GoogleMap) {
        map = googleMap
        gotoDefaultLocation()
        if (ActivityCompat.checkSelfPermission(
                requireContext(),
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                requireContext(),
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_CODE_LOCATION
            )
            return
        }

        locationPermissionGranted = true
        map.isMyLocationEnabled = true;
        //gMap.addMarker(MarkerOptions().position(devDefault).title("Hier bin ich"))

        updateLocationUI()
        getDeviceLocation()

        map.setOnMarkerClickListener(this)
        getChargePoints()
//            FetchChargePoints()
    }

    val broadCastReceiver = object : BroadcastReceiver() {
        override fun onReceive(contxt: Context?, intent: Intent?) {
            when (intent?.action) {
                SET_MAP_PERMISSIONS -> {
                    if (intent.extras?.get("result")?.toString()!!
                            .toInt() == PackageManager.PERMISSION_GRANTED
                    ) {
                        locationPermissionGranted = true
                        updateLocationUI()
                        getDeviceLocation()
                        getChargePoints()
                    }
                }
                //  BROADCAST_CHANGE_TYPE_CHANGED -> handleChangeTypeChanged()
            }
        }
    }

    @SuppressLint("MissingPermission")
    private fun updateLocationUI() {
        if (map == null) {
            return
        }
        try {
            if (locationPermissionGranted) {
                map.isMyLocationEnabled = true
                map.uiSettings.isMyLocationButtonEnabled = true
            } else {
                map.isMyLocationEnabled = false
                map.uiSettings.isMyLocationButtonEnabled = false
                lastKnownLocation = null
                getLocationPermission()
            }
        } catch (e: SecurityException) {
            Log.e("Exception: %s", e.message, e)
        }
    }

    private fun getLocationPermission() {
        /*
         * Request location permission, so that we can get the location of the
         * device. The result of the permission request is handled by a callback,
         * onRequestPermissionsResult.
         */
        if (ContextCompat.checkSelfPermission(
                requireContext(),
                Manifest.permission.ACCESS_FINE_LOCATION
            )
            == PackageManager.PERMISSION_GRANTED
        ) {
            locationPermissionGranted = true
            updateLocationUI()
        } else {
            ActivityCompat.requestPermissions(
                requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION
            )
        }
    }



    @SuppressLint("MissingPermission")
    private fun getDeviceLocation() {
        /*
         * Get the best and most recent location of the device, which may be null in rare
         * cases when a location is not available.
         */
        try {
            if (locationPermissionGranted) {
                val locationResult = fusedLocationProviderClient.lastLocation
                
                locationResult.addOnCompleteListener(requireActivity()) { task ->
                    if (task.isSuccessful) {
                        // Set the map's camera position to the current location of the device.
                        lastKnownLocation = task.result
                        if (lastKnownLocation != null) {
                            map.moveCamera(
                                CameraUpdateFactory.newLatLngZoom(
                                    LatLng(
                                        lastKnownLocation!!.latitude,
                                        lastKnownLocation!!.longitude
                                    ), DEFAULT_ZOOM.toFloat()
                                )
                            )
                        } else {
                            gotoDefaultLocation()
                        }
                    } else {
                        Log.d(TAG, "Current location is null. Using defaults.")
                        Log.e(TAG, "Exception: %s", task.exception)
                        gotoDefaultLocation()
                    }
                }
            }
        } catch (e: SecurityException) {
            MakeToast("Standort Zugriff leider nicht erlaubt")
            Log.e("Exception: %s", e.message, e)
        }
    }

    private fun gotoDefaultLocation() {
        map.moveCamera(
            CameraUpdateFactory
                .newLatLngZoom(defaultLocation, COUNTRY_ZOOM.toFloat())
        )
        map.uiSettings.isMyLocationButtonEnabled = false

    }

    private fun MakeToast(text: String) {
        val toast = text
        Toast.makeText(
            activity?.applicationContext,
            toast,
            Toast.LENGTH_SHORT
        ).show()
    }

    override fun onResume() {
        super.onResume()
        registerReceiver()
        binding.mapView.onResume()
    }

    override fun onPause() {
        super.onPause()
        binding.mapView.onPause()
    }

    override fun onStart() {
        super.onStart()
        registerReceiver()
        binding.mapView.onStart()
    }

    override fun onStop() {
        super.onStop()
        LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(broadCastReceiver)
        binding.mapView.onStop()
    }

    override fun onDestroy() {
        super.onDestroy()
//        binding.mapView.onDestroy()
    }

    private fun registerReceiver() {
        if (!isRegistered) {
            val filter = IntentFilter()
            filter.addAction(SET_MAP_PERMISSIONS)
            // filter.addAction(END_PAYMENT)
            LocalBroadcastManager.getInstance(requireContext())
                .registerReceiver(broadCastReceiver, filter)
            isRegistered = true
        }
    }


    override fun onMarkerClick(p0: Marker): Boolean {
        getCPs(p0)
        UseCpInfo()
        return true
    }

    private fun UseCpInfo() {
        if (this::cp.isInitialized) {
            CurrentChargePoint = cp // it means
//            binding.StationInfo.isVisible = true
//            val streetName = binding.StationInfo.findViewById(R.id.textViewStreet) as TextView
//            val stationCity = binding.StationInfo.findViewById(R.id.textViewCity) as TextView
//            val stationName = binding.StationInfo.findViewById(R.id.textViewStationName) as TextView
//            stationName.text = cp.getCpLocName()
//            streetName.text = cp.getStreetName()
//            stationCity.text = cp.getCityName()
//            Log.d("MapFragmentAdhok", "UseCpInfo: ${cp.hasType(ChargePointType.AdHoc)}")
//            if (cp.hasType(ChargePointType.AdHoc)) {
//                binding.textViewAvailability.text = "nur Direktladen, " + cp.Tarif + " Ct/kWh"
//            } else if (cp.Available) {
//                binding.textViewAvailability.text =
//                    String.format(Locale.GERMAN, "%.0f", cp.Tarif) + " Ct/kWh - " + String.format(
//                        Locale.GERMAN,
//                        "%.1f",
//                        cp.Power
//                    ) + " kW"
//            } else {
//                binding.textViewAvailability.text = "belegt, " + String.format(
//                    Locale.GERMAN,
//                    "%.0f",
//                    cp.Tarif
//                ) + " Ct/kWh - " + String.format(Locale.GERMAN, "%.1f", cp.Power) + " kW"
//            }
        } else {
            MakeToast("Station leider nicht verfügbar")
        }
    }

    private fun getCPs(p0: Marker) {
        for (i in 0 until ChargePoints.size) {
            if (ChargePoints[i].id == p0.id) {
                cp = ChargePoints[i]
            }
        }
    }

    private fun getCPsByCafMarker(p0: CafMarker) {
        for (i in 0 until ChargePoints.size) {
            if (ChargePoints[i].Guid == p0.GetId()) {
                cp = ChargePoints[i]
            }
        }
    }

    private fun getChargePoints() {

        viewLifecycleOwner.lifecycleScope.launchWhenCreated {
            viewModel.map.collect {
                when (it) {
                    is UiStateList.LOADING -> {

                    }
                    is UiStateList.SUCCESS -> {
                        Log.d("MapFragmentCharge", "getChargePoint: ${it.data}")
                        appCommon.setChargePoints(it.data)
                        setUpClusterer()

                    }
                    is UiStateList.ERROR -> {
                        Log.d(TAG, "getChargePoints: ${it.message}")
                        Toast.makeText(requireContext(), it.message, Toast.LENGTH_SHORT).show()
                    }
                }
            }
        }

    }
    private fun setUpClusterer() {

        val markersList = ArrayList<CafMarker>()

        clusterManager = ClusterManager<CafMarker>(activityContext, map)

        clusterManager.renderer = MapRenderer(activityContext, map, clusterManager)


        Log.d(TAG, "setUpClusterer: ${clusterManager.markerCollection}")

        map.setOnCameraIdleListener(clusterManager)
        map.setOnMarkerClickListener(clusterManager)
        map.setOnInfoWindowClickListener(clusterManager)

        clusterManager.setOnClusterItemClickListener {

            getCPsByCafMarker(it)
            UseCpInfo()
            CurrentChargePoint = cp
            appCommon.CurrentChargePoint = CurrentChargePoint
            appCommon.isAdhocBooking = CurrentChargePoint.hasType(ChargePointType.AdHoc)

            if (!appCommon.CurrentChargePoint.hasType(ChargePointType.Manual) and !appCommon.CurrentChargePoint.hasType(ChargePointType.Calibrated)) {
                Log.d("updateAccessProfileUIReserve", "addItems: ")
                appCommon.CurrentChargePoint.hasType(ChargePointType.Calibrated)
            }
//            appCommon.isCalibrated = CurrentChargePoint.hasType(ChargePointType.Calibrated)
            Log.d("TAGsetUpClusterer", "setUpClusterer: $cp")
            Log.d(TAG, "setUpClusterer: $CurrentChargePoint")


            if (sharedPref.token.length > 0) {
                Log.d("@@@@@@@", ": $sharedPref")
//                    appCommon.isAdhocBooking = false
                findNavController().navigate(R.id.navigation_reserve)
            } else {
                findNavController().navigate(R.id.navigation_settings_login)
            }

            true
        }

        clusterManager.setOnClusterClickListener { cluster ->


            // Add ten cluster items in close proximity, for purposes of this example.
            val items: List<ChargePoint> = appCommon.getChargePoints()
            var available = ""
            var tarif = ""
            var kW = ""
            for (i in cluster.items) {

                for (k in 0 until items.size) {
                    val cp: ChargePoint = items[k]

                    if (cp.Guid == i.GetId()) {

                        if (cp.hasType(ChargePointType.AdHoc) == false) {

                            Log.d("ChargePointBall", "Tarif: ${cp.Tarif}")
                            available =
                                requireContext().getResources().getString(R.string.available) + ":"
                            tarif = cp.Tarif.toInt().toString() + " Ct/kWh"
                            kW = cp.Power.toString() + " kW"
                        } else {

                            available = requireContext().getResources()
                                .getString(R.string.not_reservable) + ":"
                            tarif = cp.Tarif.toInt().toString() + " Ct/kWh"
                            kW = cp.Power.toString() + " kW"
                        }
                    }
                }

                val markerModel = CafMarker(
                    i.position.latitude,
                    i.position.longitude,
                    i.GetId(),
                    i.title,
                    i.snippet,
                    null,
                    available,
                    tarif,
                    kW
                )
                markersList.add(markerModel)


            }
            markerAdapter.submitData(markersList)
            if (markersList.size > 0) {
                showProfessionsDialog()
                markersList.clear()

                markerAdapter.itemClickListener = {
                    getCPsByCafMarker(it)
                    UseCpInfo()
                    CurrentChargePoint = cp
                    appCommon.CurrentChargePoint = CurrentChargePoint
                    Log.d("TAGsetUpClusterer", "setUpClusterer: $cp")
                    Log.d(TAG, "setUpClusterer: $CurrentChargePoint")

                    dialogMarker.dismiss()

                    if (sharedPref.token.length > 0) {
                        Log.d("@@@@@@@", ": $sharedPref")
//                    appCommon.isAdhocBooking = false
                        findNavController().navigate(R.id.navigation_reserve)
                    } else {
                        findNavController().navigate(R.id.navigation_settings_login)
                    }
                    map.moveCamera(
                        CameraUpdateFactory.newLatLngZoom(
                            LatLng(
                                it.position.latitude, it.position.longitude
                            ), DEFAULT_ZOOM.toFloat()
                        )
                    )
                }
            }
            Log.d(TAG, "setUpClusterer: clicked")
            map.animateCamera(
                CameraUpdateFactory.newLatLngZoom(
                    cluster.getPosition(),
                    Math.floor((map.cameraPosition.zoom + 1).toDouble()).toFloat()
                ), 300, null
            )
            true
        }

        addItems()

        getDeviceLocation()
    }

    private fun showProfessionsDialog() {
        dialogMarker = Dialog(requireContext())
        val binding = DialogMarkersBinding.inflate(layoutInflater)
        dialogMarker.setContentView(binding.root)
        dialogMarker.setCancelable(true)
        dialogMarker.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        binding.rvMarkers.adapter = markerAdapter
        dialogMarker.show()

    }

    override fun onInfoWindowClick(marker: Marker) {
        onMarkerClick(marker);
    }
    private fun addItems() {
        // Add ten cluster items in close proximity, for purposes of this example.
        val items: List<ChargePoint> = appCommon.getChargePoints()
        var isGood: Boolean = true
        for (i in 0 until items.size) {
            val cp: ChargePoint = items[i]
            if (cp.Guid != null) {
                Log.d("Available", "addItems: ${cp.hasType(ChargePointType.AdHoc)}")
                var color: MarkerColor = MarkerColor.Green

                if (cp.hasType(ChargePointType.AdHoc)) {
                    color = MarkerColor.Blue
                }
                else if (!cp.Available) {
                    color = MarkerColor.Red
                }
                val offsetItem = CafMarker(cp.Lat, cp.Lon, cp.Guid, cp.CpName, cp.Name, color, "", "", "")
                clusterManager.addItem(offsetItem)

                val defaultClusterRenderer = clusterManager.renderer as DefaultClusterRenderer
//                defaultClusterRenderer.minClusterSize = 4
                if (defaultClusterRenderer.minClusterSize >= 6) {
                    clusterManager.addItem(offsetItem)
                }
                cp.uuid = offsetItem.GetId()
                ChargePoints.add(i, cp)
            } else {
                isGood = false
            }
        }
        if (!isGood) {

        }
    }

    private fun createChannel(channelId: String, channelName: String) {
        // TODO: Step 1.6 START create a channel
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Create channel to show notifications.
            val notificationChannel = NotificationChannel(
                channelId,
                channelName,
                NotificationManager.IMPORTANCE_HIGH
            )
                .apply {
                    setShowBadge(false)
                }

            notificationChannel.enableLights(true)
            notificationChannel.lightColor = Color.RED
            notificationChannel.enableVibration(true)
            notificationChannel.description = getString(R.string.notification_channel_description)

            val notificationManager = requireActivity().getSystemService(
                NotificationManager::class.java
            )

            notificationManager.createNotificationChannel(notificationChannel)

        }
    }

 
}

Solution

  • Remove requireActivity(), it gives this IllegalStateException. See Explanation from official document.

    locationResult.addOnCompleteListener {task ->
        if (task.isSuccessful) {
            // Your Code
        }
    }
    

    Get Location, according to official documentation.