Home > Blockchain >  Kotlin null object reference on recyclerview when ids match
Kotlin null object reference on recyclerview when ids match

Time:05-10

I know this is a basic question but it's been doing my head in all day.

Error: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setLayoutManager(androidx.recyclerview.widget.RecyclerView$LayoutManager)' on a null object reference

As you can see below the ID for the recyclerview and where I am calling the recyclerview in mainactivity are the same, so I am really stumped as to why this is returning a null object reference. Any insight will be greatly appreciated.

MainActivity.kt

val bottomNavigation = findViewById<BottomNavigationView>(R.id.bottom_navigation)
        bottomNavigation.setOnNavigationItemSelectedListener {
            when (it.itemId) {
                R.id.ic_home -> makeCurrentFragment(homeFragment)
                R.id.ic_search -> makeCurrentFragment(searchFragment)
                R.id.ic_collections -> loadSavedRecipes()
                R.id.ic_account -> if (loggedIn) makeCurrentFragment(accountLoggedInFragment) else makeCurrentFragment(accountFragment)
            }
            true
        }

..............................

internal fun saveRecipe() {
    allSavedRecipes.add(savedRecipe)
    Toast.makeText(this, "Recipe added to favourites", Toast.LENGTH_SHORT).show()
}

private fun loadSavedRecipes() {
    makeCurrentFragment(savedRecipesFragment)
    var savedRecipeCount: Int = allSavedRecipes.count()
    if (savedRecipeCount > 0) {
        savedRecipesRV.layoutManager = GridLayoutManager(this@MainActivity, savedRecipeCount, GridLayoutManager.HORIZONTAL, false)
        savedRecipesRV.adapter = SavedRecipesAdapter(allSavedRecipes)
    }
}

SavedRecipesFragment.kt

class SavedRecipesFragment : Fragment() {

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

}

SavedRecipesAdapter

class SavedRecipesAdapter(private val savedrecipes: List<SavedRecipes>) :
    RecyclerView.Adapter<SavedRecipesAdapter.ViewHolder>(){

    override fun getItemCount(): Int {
        return savedrecipes.size
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.saved_recipes_layout, parent, false)
        )
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val theRecipe = savedrecipes.get(position)

        holder.name.text = theRecipe.title
        holder.minutes.text = theRecipe.time
        holder.servings.text = theRecipe.servings
        Picasso.get().load(theRecipe.image).into(holder.img)
    }

    class ViewHolder(view : View) : RecyclerView.ViewHolder(view) {
        val name: TextView = view.savedRecipeName
        val minutes: TextView = view.savedRecipeMinutes
        val servings: TextView = view.savedRecipeServings
        val img = view.savedRecipeImg
    }
}

saved_recipes_layout.xml

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@ id/savedRecipeCard"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@drawable/recipe_result_card_background"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@ id/savedRecipeImg"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginLeft="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintBottom_toBottomOf="@ id/savedRecipeCard"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@ id/savedRecipeCard" />

    <TextView
        android:id="@ id/savedRecipeName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:text="TextView"
        android:textColor="@color/black"
        android:textStyle="bold"
        android:textSize="20sp"
        app:layout_constraintEnd_toEndOf="@ id/savedRecipeCard"
        app:layout_constraintStart_toEndOf="@ id/savedRecipeImg"
        app:layout_constraintTop_toTopOf="@ id/savedRecipeCard" />

    <TextView
        android:id="@ id/savedRecipeMinutes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="10dp"
        android:text="75"
        android:textColor="@color/black"
        app:layout_constraintStart_toEndOf="@ id/savedRecipeImg"
        app:layout_constraintTop_toBottomOf="@ id/savedRecipeName" />

    <TextView
        android:id="@ id/savedRecipeMinutesTxt"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="5dp"
        android:text="Minutes"
        android:textColor="@color/black"
        app:layout_constraintEnd_toEndOf="@ id/savedRecipeCard"
        app:layout_constraintStart_toEndOf="@ id/savedRecipeMinutes"
        app:layout_constraintTop_toBottomOf="@ id/savedRecipeName" />

    <TextView
        android:id="@ id/savedRecipeServings"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="564"
        android:textColor="@color/black"
        app:layout_constraintStart_toEndOf="@ id/savedRecipeImg"
        app:layout_constraintTop_toBottomOf="@ id/savedRecipeMinutes" />

    <TextView
        android:id="@ id/savedRecipeServingsTxt"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="Servings"
        android:textColor="@color/black"
        app:layout_constraintEnd_toEndOf="@ id/savedRecipeCard"
        app:layout_constraintStart_toEndOf="@ id/savedRecipeMinutes"
        app:layout_constraintTop_toBottomOf="@ id/savedRecipeMinutesTxt" />



</androidx.constraintlayout.widget.ConstraintLayout>

fragment_saved_recipes.xml

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

    <TextView
        android:id="@ id/savedRecipesHeader"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="My Saved Recipes"
        android:textColor="@color/black"
        android:textAlignment="center"
        android:textStyle="bold"
        android:textSize="24sp"
        android:layout_marginVertical="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:fadeScrollbars="true"
        android:overScrollMode="never"
        android:scrollbars="vertical"
        android:layout_marginTop="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@ id/savedRecipesHeader">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@ id/savedRecipesRV"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:overScrollMode="never" />

        </LinearLayout>

    </androidx.core.widget.NestedScrollView>


</androidx.constraintlayout.widget.ConstraintLayout>

CodePudding user response:

Most likely you are trying to set a layout manager before the OnCreateView() is called. You can actually just add a layout manager from XML if you like:

 <androidx.recyclerview.widget.RecyclerView
                android:id="@ id/savedRecipesRV"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:overScrollMode="never" 
               app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"

/>

but it would definitely be best to set up your UI components after they are inflated. You can do that in onViewCreated, onResume, or onStart depending on your needs.

CodePudding user response:

Solved through handling the functionality through the fragment class:

class SavedRecipesFragment : Fragment() {

lateinit var savedRecipesRV: RecyclerView
var allSavedRecipesPass = mutableListOf<SavedRecipes>()

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    val view = inflater.inflate(R.layout.fragment_saved_recipes, container, false)
    savedRecipesRV = view.findViewById(R.id.savedRecipesRecyclerView)
    return view
}

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

override fun onResume() {
    super.onResume()
    DisplaySavedRecipes()
}

fun DisplaySavedRecipes() {
    allSavedRecipesPass = (activity as MainActivity).allSavedRecipes
    
    var savedRecipeCount: Int = allSavedRecipesPass.count()

    if (savedRecipeCount > 0) {
        savedRecipesRV.layoutManager = GridLayoutManager(context, savedRecipeCount, GridLayoutManager.HORIZONTAL, false)
        savedRecipesRV.adapter = SavedRecipesAdapter(allSavedRecipesPass)
    }
}

}

  • Related