如何实现“最喜欢的”按钮功能(如最喜欢的食谱/食物)并显示在另一个片段的另一个列表中
Posted
技术标签:
【中文标题】如何实现“最喜欢的”按钮功能(如最喜欢的食谱/食物)并显示在另一个片段的另一个列表中【英文标题】:How to implement "favourite" button feature (like favourite recipe/food) and display on another list in another fragment 【发布时间】:2021-10-19 14:05:29 【问题描述】:我想要一个功能,当用户单击某一行上的按钮时,它将将该行添加到另一个列表中,该列表称为收藏列表。目前我已经创建了包含收藏状态的数据库。我已经尝试从创建一个按钮开始,单击该按钮将更改收藏状态。 我还是android studio的新手,刚学了半个月。所以对我放轻松。我目前遇到此错误:
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)
食谱.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_
android:layout_>
<androidx.cardview.widget.CardView
android:id="@+id/row_cardView"
android:layout_
android:layout_
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_
android:layout_
android:background="@color/white">
<ImageView
android:id="@+id/recipe_imageView"
android:layout_
android:layout_
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_
android:layout_
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_
android:layout_
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_
android:layout_
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>
【问题讨论】:
【参考方案1】:当您尝试使用在使用前未初始化的对象时,可能会出现以下错误。表示它处于空状态,因为您可以看到 RecyclerViewAdapter 中的 db 对象未初始化。
要解决这个问题,只需在使用它之前初始化对象或检查它是否不为空。
在你的情况下,照做
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
....
【讨论】:
以上是关于如何实现“最喜欢的”按钮功能(如最喜欢的食谱/食物)并显示在另一个片段的另一个列表中的主要内容,如果未能解决你的问题,请参考以下文章