I want to have a feature that when the user clicked the button on a certain row, it will add the row to another list which is called favorite list. Currently i have created database that also include favourite status. I already tried to start with creating a button that when its clicked it will change the fav status. Im still new on android studio, just learnt for half a month. So go easy on me. I am currently stuck on this error:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.myapplication, PID: 13778 java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.myapplication.data.DatabaseHandler.addRecipe(com.example.myapplication.model.Recipe)' on a null object reference at com.example.myapplication.adapter.RecyclerViewAdapter$ViewHolder$1.onClick(RecyclerViewAdapter.java:123) at android.view.View.performClick(View.java:7448) at android.view.View.performClickInternal(View.java:7425) at android.view.View.access$3600(View.java:810) at android.view.View$PerformClick.run(View.java:28305) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Recipe.java
public class Recipe { private int id; private String name; private String description; private String ingredient; private int image; private String favStatus; public Recipe() { } public Recipe(int id, String name, String description, String ingredient, int image, String favStatus) { this.id = id; this.name = name; this.description = description; this.ingredient = ingredient; this.image = image; this.favStatus = favStatus; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getIngredient() { return ingredient; } public void setIngredient(String ingredient) { this.ingredient = ingredient; } public int getImage() { return image; } public void setImage(int image) { this.image = image; } public String getFavStatus() { return favStatus; } public void setFavStatus(String favStatus) { this.favStatus = favStatus; } }
DatabaseHandler.java
public class DatabaseHandler extends SQLiteOpenHelper { public DatabaseHandler(Context context) { super(context, Util.DATABASE_NAME, null, Util.DATABASE_VERSION); } //We create our table.. @Override public void onCreate(SQLiteDatabase db) { //SQL- Structured Query Language /* create table _name(id, name, desc, ingredient, image); */ String CREATE_CONTACT_TABLE = "CREATE TABLE " + Util.TABLE_NAME + "(" + Util.KEY_ID + " INTEGER PRIMARY KEY," + Util.KEY_NAME + " TEXT," + Util.KEY_DESCRIPTION + " TEXT," + Util.KEY_INGREDIENT + " TEXT," + Util.KEY_IMAGE + " BLOB," + Util.KEY_FAV_STATUS + " TEXT" + ")"; db.execSQL(CREATE_CONTACT_TABLE); //Creating our table.. } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String DROP_TABLE = String.valueOf(R.string.db_drop); db.execSQL(DROP_TABLE, new String[]{Util.DATABASE_NAME}); //Create table again onCreate(db); } //Add Recipe public void addRecipe(Recipe recipe) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(Util.KEY_NAME, recipe.getName()); values.put(Util.KEY_DESCRIPTION, recipe.getDescription()); values.put(Util.KEY_INGREDIENT, recipe.getIngredient()); values.put(Util.KEY_IMAGE, recipe.getImage()); values.put(Util.KEY_FAV_STATUS, recipe.getFavStatus()); //Insert into row.. db.insert(Util.TABLE_NAME, null, values); Log.d("DBHandler", "addRecipe: " + "item added"); db.close(); } //Get a recipe public Recipe getRecipe(int id) { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.query(Util.TABLE_NAME, new String[] { Util.KEY_ID, Util.KEY_NAME, Util.KEY_DESCRIPTION, Util.KEY_FAV_STATUS, Util.KEY_INGREDIENT, Util.KEY_IMAGE}, Util.KEY_ID +"=?", new String[]{String.valueOf(id)}, null, null, null); if (cursor != null) cursor.moveToFirst(); Recipe recipe = new Recipe(); recipe.setId(Integer.parseInt(cursor.getString(0))); recipe.setName(cursor.getString(1)); recipe.setDescription(cursor.getString(2)); recipe.setIngredient(cursor.getString(3)); recipe.setImage(Integer.parseInt(cursor.getString(4))); recipe.setFavStatus(cursor.getString(5)); return recipe; } //Get all Recipes public List<Recipe> getAllRecipes() { List<Recipe> recipeList = new ArrayList<>(); SQLiteDatabase db = this.getReadableDatabase(); //Select all recipes String selectAll = "SELECT * FROM " + Util.TABLE_NAME; Cursor cursor = db.rawQuery(selectAll, null); //Loop through our data if (cursor.moveToFirst()) { do { Recipe recipe = new Recipe(); recipe.setId(Integer.parseInt(cursor.getString(0))); recipe.setName(cursor.getString(1)); recipe.setDescription(cursor.getString(2)); recipe.setIngredient(cursor.getString(3)); recipe.setImage(Integer.parseInt(cursor.getString(4))); recipe.setFavStatus((cursor.getString(5))); //add recipe objects to our list recipeList.add(recipe); }while (cursor.moveToNext()); } return recipeList; } //Update recipe public int updateRecipe (Recipe recipe) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(Util.KEY_NAME, recipe.getName()); values.put(Util.KEY_DESCRIPTION, recipe.getDescription()); values.put(Util.KEY_INGREDIENT, recipe.getIngredient()); values.put(Util.KEY_IMAGE, recipe.getImage()); values.put(Util.KEY_FAV_STATUS, recipe.getFavStatus()); //Update the row return db.update(Util.TABLE_NAME, values, Util.KEY_ID + "=?", new String[]{String.valueOf(recipe.getId())}); } //Delete single recipe public void deleteRecipe(Recipe recipe) { SQLiteDatabase db = this.getWritableDatabase(); db.delete(Util.TABLE_NAME, Util.KEY_ID + "=?", new String[]{String.valueOf(recipe.getId())}); db.close(); } //Select all favorite list method. public List<Recipe> getAllFavRecipes() { List<Recipe> recipeList = new ArrayList<>(); SQLiteDatabase db = this.getReadableDatabase(); //Select all recipes String selectAll = "SELECT * FROM " + Util.TABLE_NAME + " WHERE " + Util.KEY_FAV_STATUS + " ='1'"; Cursor cursor = db.rawQuery(selectAll, null); //Loop through our data if (cursor.moveToFirst()) { do { Recipe recipe = new Recipe(); recipe.setId(Integer.parseInt(cursor.getString(0))); recipe.setName(cursor.getString(1)); recipe.setDescription(cursor.getString(2)); recipe.setIngredient(cursor.getString(3)); recipe.setImage(Integer.parseInt(cursor.getString(4))); recipe.setFavStatus((cursor.getString(5))); //add recipe objects to our list recipeList.add(recipe); }while (cursor.moveToNext()); } return recipeList; } }
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements Filterable{ private Context context; private List<Recipe> recipeList; private List<Recipe> recipeListFull; private DatabaseHandler db; public RecyclerViewAdapter(Context context, List<Recipe> recipeList) { this.context = context; this.recipeList = recipeList; recipeListFull = new ArrayList<>(recipeList); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View view = LayoutInflater.from(viewGroup.getContext()) .inflate(R.layout.recipe_row, viewGroup, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { Recipe recipe = recipeList.get(position); //each recipe object inside of our list viewHolder.recipeName.setText(recipe.getName()); viewHolder.description.setText(recipe.getDescription()); viewHolder.image.setImageResource(recipe.getImage()); } @Override public int getItemCount() { return recipeList.size(); } @Override public Filter getFilter() { return filterRecipe; } private Filter filterRecipe = new Filter() { @Override protected FilterResults performFiltering(CharSequence charSequence) { String searchText = charSequence.toString().toLowerCase(); List<Recipe> tempList = new ArrayList<>(); if(searchText.length()==0 | searchText.isEmpty()) { tempList.addAll(recipeListFull); }else { for (Recipe item:recipeListFull) { if (item.getName().toLowerCase().contains(searchText)) { tempList.add(item); } } } FilterResults filterResults = new FilterResults(); filterResults.values = tempList; return filterResults; } @Override protected void publishResults(CharSequence constraint, FilterResults filterResults) { recipeList.clear(); recipeList.addAll((Collection<? extends Recipe>) filterResults.values); notifyDataSetChanged(); } }; public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public TextView recipeName; public TextView description; public ImageView image; public ImageView favBtn; public ViewHolder(@NonNull View itemView) { super(itemView); itemView.setOnClickListener(this); recipeName = itemView.findViewById(R.id.name); description = itemView.findViewById(R.id.description); image = itemView.findViewById(R.id.recipe_imageView); favBtn = itemView.findViewById(R.id.fav_image_btn); favBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int position = getAdapterPosition(); Recipe recipe = recipeList.get(position); if (recipe.getFavStatus().equals("0")) { recipe.setFavStatus("1"); db.addRecipe(recipe); favBtn.setImageResource(R.drawable.favourite_star); } else { recipe.setFavStatus("0"); db.deleteRecipe(recipe); favBtn.setImageResource(R.drawable.shadow_fav_star); } } }); } @Override public void onClick(View v) { int position = getAdapterPosition(); Recipe recipe = recipeList.get(position); Intent intent = new Intent(context, DetailsActivity.class); intent.putExtra("name", recipe.getName()); intent.putExtra("description", recipe.getDescription()); intent.putExtra("ingredient", recipe.getIngredient()); intent.putExtra("image", recipe.getImage()); context.startActivity(intent); //Log.d("Clicked", "onClick: " + recipe.getName()); } } //Create method to read and check for fav status for every row.. }
recipeRow.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="wrap_content"> <androidx.cardview.widget.CardView android:id="@+id/row_cardView" android:layout_width="0dp" android:layout_height="150dp" android:layout_marginStart="1dp" android:layout_marginTop="2dp" android:layout_marginEnd="1dp" app:cardCornerRadius="15dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white"> <ImageView android:id="@+id/recipe_imageView" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginStart="3dp" android:scaleType="centerCrop" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> <TextView android:id="@+id/name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginTop="7dp" android:layout_marginEnd="12dp" android:ellipsize="end" android:fontFamily="@font/courgette" android:maxLines="2" android:text="Title Text" android:textColor="@color/darker" android:textSize="28sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.007" app:layout_constraintStart_toEndOf="@+id/recipe_imageView" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/description" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:ellipsize="end" android:maxLines="3" android:text="Desc Text" android:textSize="13sp" android:textColor="@color/darkGray" app:layout_constraintBottom_toTopOf="@+id/fav_image_btn" app:layout_constraintEnd_toEndOf="@+id/name" app:layout_constraintStart_toStartOf="@+id/name" app:layout_constraintTop_toBottomOf="@+id/name" /> <ImageView android:id="@+id/fav_image_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="25dp" android:layout_marginBottom="7dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:srcCompat="@drawable/favourite_star" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> </androidx.constraintlayout.widget.ConstraintLayout>
Advertisement
Answer
The following error can occur when you try to use object which is not initialised before using it. means it’s in null state, as you can see your db object in RecyclerViewAdapter is not initialised.
to solve this just initialised the object before using it or check if it’s not null.
in you case just do as
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements Filterable{ .... private DatabaseHandler db; // object declared here public RecyclerViewAdapter(Context context, List<Recipe> recipeList) { this.context = context; this.recipeList = recipeList; recipeListFull = new ArrayList<>(recipeList); db = new DatabaseHandler(context); // db object initialised here } .... }