How to initialized "lateinit binding" in a fragment?

Issue

I am trying to add a listener to my button from a Fragment but it always give me this error:

 Process: com.example.projectdrivemark, PID: 27776
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.projectdrivemark/com.example.MainActivity}: kotlin.UninitializedPropertyAccessException: lateinit property binding has not been initialized
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3341)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3485)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2045)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7478)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
     Caused by: kotlin.UninitializedPropertyAccessException: lateinit property binding has not been initialized
        at com.example.tempConverter.TempConverterFragment.<init>(TempConverterFragment.kt:16)
        at com.example.MainActivity.onCreate(MainActivity.kt:28)
        at android.app.Activity.performCreate(Activity.java:7989)
        at android.app.Activity.performCreate(Activity.java:7978)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3316

Here is MainActivity code:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.projectdrivemark.R
import com.example.projectdrivemark.databinding.ActivityMainBinding
import com.example.recyclerView.MockDatabase.Companion.createMockData
import com.example.recyclerView.PostAdapter
import com.example.recyclerView.RecyclerViewFragment
import com.example.tempConverter.TempConverterFragment
import com.example.uploaderView.UploaderFragment

class MainActivity : AppCompatActivity(), PostAdapter.OnPostClickListener {
    private lateinit var binding: ActivityMainBinding
    val dummyList = createMockData()
    val adapter = PostAdapter(dummyList, this)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        title = "First Kotlin App"
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val recyclerView = RecyclerViewFragment()
        val tempConverterView = TempConverterFragment()
        val uploaderView = UploaderFragment(this)
        setFragmentView(recyclerView)

        binding.bottomNavBar.setOnNavigationItemSelectedListener {
            when(it.itemId){
                R.id.listView ->  setFragmentView(recyclerView)
                R.id.tempConverterView -> setFragmentView(tempConverterView)
                R.id.videoUploaderView -> setFragmentView(uploaderView)
            }
            true
        }
    }

    private fun setFragmentView(fragment: Fragment){
        supportFragmentManager.beginTransaction().apply {
            replace(R.id.main_fragment_view, fragment)
            //Will return to previous page when tap "Back Button" on the phone
            addToBackStack(null)
            commit()
        }
    }

    override fun onEditPost(position: Int){
        val clickedPost = dummyList[position]
        clickedPost.title = "Updated title"
        clickedPost.body = "Updated body"
        adapter.notifyItemChanged(position)
    }

    override fun onDeletePost(position: Int) {
        dummyList.removeAt(position)
  

  adapter.notifyItemRemoved(position)
}

}

Here is how my TempConverterFragment looks like:

import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.example.MainActivity
import com.example.projectdrivemark.R
import com.example.projectdrivemark.databinding.FragmentTempConverterBinding

class TempConverterFragment: Fragment(){
    private lateinit var binding: FragmentTempConverterBinding
    val celsiusButton = binding.celsiusButton


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val binding = inflater.inflate(R.layout.fragment_temp_converter, container, false)
        celsiusButton.setOnClickListener {
            celsiusFunction(celsiusButton)
        }
        return binding.rootView

    }

    fun celsiusFunction(view: View){
        val fahrenheitView = binding!!.userTemp
        val fahrenheitValue = fahrenheitView.text.toString()

        if(!fahrenheitValue.isBlank()){
            val celsiusCovertedValue = (fahrenheitValue.toDouble() - 32) * 5/9
            val celsiusValue = String.format("%.2f", celsiusCovertedValue)
            Toast.makeText(activity,
                    "$fahrenheitValue fahrenheit is $celsiusValue degrees celsius",
                    Toast.LENGTH_LONG).show()
        }else {
            Toast.makeText(activity, "You must enter a value to convert", Toast.LENGTH_LONG).show()
        }
    }

    fun farenheitFunction(view: View){
        val celsiusView = binding.userTemp
        val celsiusValue = celsiusView.text.toString()

        if(!celsiusValue.isBlank()){
            val farenheitConvertedValue = celsiusValue.toDouble() * 9/5 + 32
            val farenheitValue = String.format("%.2f", farenheitConvertedValue)
            Toast.makeText(activity,
                    "$celsiusValue degrees celsius is $farenheitValue farenheit",
                    Toast.LENGTH_LONG).show()
        }else{
            Toast.makeText(activity, "You must enter a value to convert", Toast.LENGTH_LONG).show()
        }
    }
}

And here is how my Xml Fragment looks like:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="487dp"
        android:layout_height="320dp"
        android:layout_marginBottom="16dp"
        android:adjustViewBounds="true"
        android:cropToPadding="false"
        android:scaleType="fitXY"
        app:layout_constraintBottom_toTopOf="@+id/textView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:srcCompat="@drawable/termometer" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="62dp"
        android:layout_marginLeft="62dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="76dp"
        android:layout_marginRight="76dp"
        android:text="Enter desired temperature to convert"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />

    <EditText
        android:id="@+id/userTemp"
        style="@android:style/Widget.DeviceDefault.EditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="140dp"
        android:layout_marginLeft="140dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="140dp"
        android:layout_marginRight="140dp"
        android:ems="10"
        android:hint="Enter Temperature Here"
        android:inputType="numberDecimal"
        android:selectAllOnFocus="false"
        android:singleLine="true"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <Button
        android:id="@+id/celsiusButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="70dp"
        android:layout_marginLeft="70dp"
        android:layout_marginTop="32dp"
        android:onClick="celsiusFunction"
        android:text="to Celsius"
        app:backgroundTint="@color/purple_200"
        app:layout_constraintEnd_toStartOf="@+id/farenheitButton"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/userTemp" />

    <Button
        android:id="@+id/farenheitButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="41dp"
        android:layout_marginLeft="41dp"
        android:layout_marginTop="32dp"
        android:layout_marginEnd="72dp"
        android:layout_marginRight="72dp"
        android:onClick="farenheitFunction"
        android:text="to Farenheit"
        app:backgroundTint="@color/teal_200"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/celsiusButton"
        app:layout_constraintTop_toBottomOf="@+id/userTemp" />
</androidx.constraintlayout.widget.ConstraintLayout>

How to initialize a lateinit binding? Or is it better just use view.findViewById?

Solution

Remove the val before the variable binding in your onCreateView of your fragment because you have already declared it and initialized it like below:

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 
{
    binding = FragmentTempConverterBinding.inflate(inflater, container, false)
    return binding.root
}

Answered By – Greeshma

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published