androidkotlinandroid-fragmentsnullpointerexceptioncontainer-view

Why does findViewById returning null when searching for the RecyclerView?


Why is val rv: RecyclerView = findViewById(R.id.material_list_rv) returning null?

MainActivity

class MainActivity : AppCompatActivity() {

    var adaptor: MaterialListAdaptor = MaterialListAdaptor()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (savedInstanceState == null) {
            supportFragmentManager.commit {
                setReorderingAllowed(true)
                add<MaterialListFragment>(R.id.fragment_container_view)
            }
        }

        initRecyclerView()
        setRecyclerViewData()

    }

    private fun initRecyclerView(){
        val rv: RecyclerView = findViewById(R.id.material_list_rv)
        rv.layoutManager = LinearLayoutManager(this@MainActivity)
        rv.adapter = adaptor
    }

    private fun setRecyclerViewData(){
        val l = DataSource.createMaterialList()
        adaptor.setDataSet(l)
    }
}

activity_main

<?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=".MainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragment_container_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

MaterialListFragment

class MaterialListFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.fragment_material_list, container, false)
    }
}

fragment_material_list

<?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=".MaterialListFragment">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/material_list_rv"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:listitem="@layout/material_list_rv_list_item" />

</androidx.constraintlayout.widget.ConstraintLayout>

Solution

  • The problem

    You placed the call to findViewById in MainActivity.onCreate. It's too early for that, the Fragment's view hasn't been created at that point.

    You should be looking for the view in your MaterialListFragment. If you call findViewById in onCreateView, it will work. Like this:

    val root = inflater.inflate(R.layout.fragment_material_list, container, false)
    val rv = root.findViewById(R.id. material_list_rv)
    
    // Do whatever (eg assign rv to a field in the Fragment to use it later)
    
    return root
    

    Some advice

    Even if your code worked, try to have Activities, Fragments and custom Views manage their own children.

    If the upper containers dive deep into their children, it's very easy to make mistakes (like the one here!) and you lose the ability to update internal details of Fragments and Views without breaking the containing Activity.

    Activity/Fragment lifecycle chart

    To orient yourself, keep this in mind (though this diagram is EXTREMELY simplified):

    enter image description here