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