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)
}
}
}
