Why does findViewById returning null when searching for the RecyclerView?

114 Views Asked by At

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>
2

There are 2 best solutions below

1
On BEST ANSWER

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

0
On

You are looking for RecylerView in MainActivity, where it does not exist. Instead you should try to access it in FragmentActivity.