Home > Blockchain >  Kotlin - lateinit property fragmentHomeBinding has not been initialized
Kotlin - lateinit property fragmentHomeBinding has not been initialized

Time:05-21

I am working on a kotlin application that contains fragments. I am converting an app I created using activity to fragments but I am having an issue. I get an error when running the app that the property fragmentHomeBinding has not been initialized and the app closes.

Here's the fragment Home.kt

class Home : Fragment() {

    private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
    private lateinit var fragmentHomeBinding: FragmentHomeBinding


    @SuppressLint("WrongViewCast")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)


        getCurrentLocation()

        fragmentHomeBinding.etGetCityName.setOnEditorActionListener { v, actionId, keyEvent ->
            if(actionId == EditorInfo.IME_ACTION_SEARCH)
            {
                getCityWeather(fragmentHomeBinding.etGetCityName.text.toString())
                val view = activity?.currentFocus
                if(view!=null)
                {
                    val imm:InputMethodManager=
                        activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    imm.hideSoftInputFromWindow(view.windowToken, 0)
                    fragmentHomeBinding.etGetCityName.clearFocus()
                }
                true
            }
            else false
        }

    }

    private fun getCityWeather(cityName:String)
    {
        fragmentHomeBinding.pbLoading.visibility = View.VISIBLE
        ApiUtilities.getApiInterface()?.getCityWeatherData(cityName, API_KEY)?.enqueue(
            object:Callback<ModelClass>{
                override fun onResponse(call: Call<ModelClass>, response: Response<ModelClass>) {
                    setDataOnViews((response.body()))
                }

                override fun onFailure(call: Call<ModelClass>, t: Throwable) {
                    Toast.makeText(activity?.applicationContext, "Wrong City", Toast.LENGTH_SHORT).show()
                }

            })
    }

    private fun getCurrentLocation()
    {
        if(checkPermission())
        {
            if(isLocationEnabled())
            {
                if(ActivityCompat.checkSelfPermission(
                        requireActivity(), android.Manifest.permission.ACCESS_FINE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                        requireActivity(),
                        android.Manifest.permission.ACCESS_COARSE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED
                ){
                    requestPermission()
                    return
                }
                fusedLocationProviderClient.lastLocation.addOnCompleteListener(requireActivity()){ task->
                    val location: Location?=task.result
                    if(location==null)
                    {
                        fetchCurrentLocationWeather(23.76137119142536.toString(), 90.35059989467042.toString())
                    }
                    else
                    {
                        fetchCurrentLocationWeather(location.latitude.toString(),location.longitude.toString())
                    }
                }

            }
            else
            {
                Toast.makeText(activity?.applicationContext, "Turn on Location", Toast.LENGTH_SHORT).show()
                val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
                startActivity(intent)
            }
        }
    }

    private fun fetchCurrentLocationWeather(latitude: String, longitude:String)
    {
        fragmentHomeBinding.pbLoading.visibility = View.VISIBLE
        ApiUtilities.getApiInterface()?.getCurrentWeatherData(latitude, longitude, API_KEY)?.enqueue(
            object : Callback<ModelClass> {
                override fun onResponse(call: Call<ModelClass>, response: Response<ModelClass>) {
                    if(response.isSuccessful)
                    {
                        setDataOnViews(response.body())
                    }
                }

                override fun onFailure(call: Call<ModelClass>, t: Throwable) {
                    Toast.makeText(activity?.applicationContext, "ERROR", Toast.LENGTH_SHORT).show()
                }

            })
    }

    private fun setDataOnViews(body: ModelClass?) {
        val sdf = SimpleDateFormat("dd/MM/yyyy hh:mm")
        val currentDate = sdf.format(Date())
        fragmentHomeBinding.tvDateTime.text = currentDate
        fragmentHomeBinding.tvDayMaxTemp.text = "" kelvinToCelsius(body!!.main.temp_max)   "°"
        fragmentHomeBinding.tvDayMinTemp.text = "" kelvinToCelsius(body!!.main.temp_min)   "°"
        fragmentHomeBinding.tvTemp.text = "" kelvinToCelsius(body!!.main.temp)
        fragmentHomeBinding.tvFeelsLike.text = "Feels like: " kelvinToCelsius(body!!.main.feels_like)   "°"
        fragmentHomeBinding.tvWeatherType.text = body.weather[0].main
        fragmentHomeBinding.tvPressure.text = body.main.pressure.toString()
        fragmentHomeBinding.tvHumidity.text = body.main.humidity.toString()   " %"
        fragmentHomeBinding.tvWindSpeed.text = body.wind.speed.toString()   " m/s"
        fragmentHomeBinding.tvCityName.text = body.name
        updateUI(body.weather[0].id)
    }


    private fun updateUI(id: Int) {
        fragmentHomeBinding.pbLoading.visibility = View.GONE
        fragmentHomeBinding.mainLayout.visibility = View.VISIBLE
    }

    private fun kelvinToCelsius(temp: Double): Double
    {
    var intTemp = temp
        intTemp = intTemp.minus(273)
        return intTemp.toBigDecimal().setScale(1, RoundingMode.UP).toDouble()
    }


    companion object
    {
        const val PERMISSION_REQUEST_ACCESS_LOCATION = 100
        const val API_KEY = "3c709ccaf2730aa1c263925f75db631a"
    }

    private fun isLocationEnabled():Boolean{
        val locationManager:LocationManager=activity?.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
            LocationManager.NETWORK_PROVIDER
        )
    }

    private fun requestPermission(){
        ActivityCompat.requestPermissions(
            requireActivity(), arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION,
            android.Manifest.permission.ACCESS_FINE_LOCATION),
            PERMISSION_REQUEST_ACCESS_LOCATION
        )
    }

    private fun checkPermission():Boolean{
        if(ActivityCompat.checkSelfPermission(requireActivity(),
            android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(requireActivity(),
            android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
        {
            return true
        }
        return false
    }

    @Suppress("DEPRECATION")
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if(requestCode== PERMISSION_REQUEST_ACCESS_LOCATION)
        {
            if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(activity?.applicationContext, "Granted", Toast.LENGTH_SHORT).show()
                getCurrentLocation()
            }
            else{
                Toast.makeText(activity?.applicationContext, "Denied", Toast.LENGTH_SHORT).show()
            }
        }
    }



    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?): View? {
        fragmentHomeBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
        // Inflate the layout for this fragment
        return fragmentHomeBinding.root
    }


}

Here's the error that shows up on logcat:

2022-05-20 17:45:20.582 22026-22048/com.example.weather D/EGL_emulation: app_time_stats: avg=30.74ms min=18.05ms max=34.54ms count=33
2022-05-20 17:45:21.416 22026-22026/com.example.weather D/AndroidRuntime: Shutting down VM
2022-05-20 17:45:21.417 22026-22026/com.example.weather E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.weather, PID: 22026
    kotlin.UninitializedPropertyAccessException: lateinit property fragmentHomeBinding has not been initialized
        at com.example.weather.Home.onCreate(Home.kt:58)
        at androidx.fragment.app.Fragment.performCreate(Fragment.java:2949)
        at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:278)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3138)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1455)
        at android.app.Activity.performStart(Activity.java:8076)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3660)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7839)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
2022-05-20 17:45:21.435 22026-22026/com.example.weather I/Process: Sending signal. PID: 22026 SIG: 9

Help's appreciated, thanks.

CodePudding user response:

Your Fragment viewbinding instance fragmentHomeBinding is initialised at onCreateView() life cycle method. But you are accessing at onCreate() lifecycle method. In Fragment lifecycle, onCreate() will be called before onCreatedView().

enter image description here

As a result you are accessing an object which is not initialised. To resolve the issue, move your viewbinding reference code in onCreate() to onCreateView() as below.

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?): View? {
        fragmentHomeBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)

fragmentHomeBinding.etGetCityName.setOnEditorActionListener { v, actionId, keyEvent ->
            if(actionId == EditorInfo.IME_ACTION_SEARCH)
            {
                getCityWeather(fragmentHomeBinding.etGetCityName.text.toString())
                val view = activity?.currentFocus
                if(view!=null)
                {
                    val imm:InputMethodManager=
                        activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    imm.hideSoftInputFromWindow(view.windowToken, 0)
                    fragmentHomeBinding.etGetCityName.clearFocus()
                }
                true
            }
            else false
        }

        // Inflate the layout for this fragment
        return fragmentHomeBinding.root
    }
  • Related