java - 如何实现“最喜欢的”按钮功能(如最喜欢的食谱/食物)并显示在另一个片段的另一个列表中
问题描述
我想要一个功能,当用户单击某行上的按钮时,它将将该行添加到另一个称为收藏列表的列表中。目前我已经创建了包含收藏状态的数据库。我已经尝试从创建一个按钮开始,单击该按钮将更改收藏状态。我还是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;
}
}
数据库处理程序.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..
}
食谱行.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>
解决方案
当您尝试使用在使用之前未初始化的对象时,可能会发生以下错误。表示它处于空状态,因为您可以看到 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
}
....
}
推荐阅读
- lme4 - glmer 中的交互(统计建议)
- nginx - 当位置 URI 不是 root 时,nginx proxypass 失败“GET”请求
- windows - git CMD 找到 .gitconfig 但 Windows cmd 没有?
- docker-swarm - Traefik 无法路由到具有已发布端口的容器
- python - 当路径中有“\v”时打开文件
- sql - SQL Faster 检查表中有限数量的 id
- oracle-apex-18.2 - 无法删除全局页面
- php - 无法在 PHP 中使用 curl 从 API 获取 json 响应
- c# - C# 连接字符串到 MS Teams 上的 MS 访问文件
- php - 试图获取非对象错误的属性 - Laravel