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