如何在RecyclerView的GridView中展示数据库内的菜谱?
实现带GridView的RecyclerView展示数据库菜谱的方案
首先,我梳理下你的需求:用一个每个Item包含GridView的RecyclerView,从你现有的SQLite数据库里读取菜谱数据并展示。下面一步步给你讲怎么实现:
1. 完善MyDBHandler,添加数据查询方法
你的MyDBHandler目前只定义了基础常量,得先补上数据库操作的核心方法,才能从库里拿到菜谱数据:
public class MyDBHandler extends SQLiteOpenHelper { public static final String DATABASE_NAME = "Recipes.db"; public static final int DATABASE_VERSION = 1; // 必须添加版本号 public static final String TABLE_RECIPE = "recipe_table"; public static final String COLUMN_ID = "recipe_id"; public static final String COLUMN_RECIPENAME = "recipe_name"; // 补全构造方法(你之前的代码没写完,这里给你补全) public MyDBHandler(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { // 创建菜谱表的SQL语句 String CREATE_RECIPE_TABLE = "CREATE TABLE " + TABLE_RECIPE + "(" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_RECIPENAME + " TEXT NOT NULL" + ")"; db.execSQL(CREATE_RECIPE_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 升级时先删旧表(如果需要保留数据,这里要做数据迁移逻辑) db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECIPE); onCreate(db); } // 获取所有菜谱名称的方法 public List<String> getAllRecipeNames() { List<String> recipeList = new ArrayList<>(); SQLiteDatabase db = this.getReadableDatabase(); String query = "SELECT " + COLUMN_RECIPENAME + " FROM " + TABLE_RECIPE; Cursor cursor = db.rawQuery(query, null); if (cursor.moveToFirst()) { do { String recipeName = cursor.getString(cursor.getColumnIndex(COLUMN_RECIPENAME)); recipeList.add(recipeName); } while (cursor.moveToNext()); } cursor.close(); db.close(); return recipeList; } // 拓展:如果以后菜谱有更多字段(食材、步骤),可以创建Recipe实体类,返回完整对象列表 // public List<Recipe> getAllRecipes() { // List<Recipe> recipeList = new ArrayList<>(); // SQLiteDatabase db = this.getReadableDatabase(); // String query = "SELECT * FROM " + TABLE_RECIPE; // Cursor cursor = db.rawQuery(query, null); // if (cursor.moveToFirst()) { // do { // Recipe recipe = new Recipe(); // recipe.setId(cursor.getInt(cursor.getColumnIndex(COLUMN_ID))); // recipe.setName(cursor.getString(cursor.getColumnIndex(COLUMN_RECIPENAME))); // recipeList.add(recipe); // } while (cursor.moveToNext()); // } // cursor.close(); // db.close(); // return recipeList; // } }
2. (可选但推荐)创建Recipe实体类
如果以后你的菜谱会增加更多属性,提前建一个实体类会让代码更整洁:
public class Recipe { private int id; private String name; public Recipe() {} public Recipe(int id, String name) { this.id = id; this.name = name; } // Getter和Setter方法 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; } }
3. 实现GridView的适配器(RecyclerView Item内的GridView)
先写GridView的适配器,用来展示单组菜谱:
public class GridRecipeAdapter extends BaseAdapter { private Context mContext; private List<String> mRecipeList; // 如果用Recipe实体类,改成List<Recipe> public GridRecipeAdapter(Context context, List<String> recipeList) { this.mContext = context; this.mRecipeList = recipeList; } @Override public int getCount() { return mRecipeList.size(); } @Override public Object getItem(int position) { return mRecipeList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.grid_item_recipe, parent, false); holder = new ViewHolder(); holder.recipeNameTv = convertView.findViewById(R.id.tv_recipe_name); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } // 设置菜谱名称 holder.recipeNameTv.setText(mRecipeList.get(position)); // 如果用实体类:holder.recipeNameTv.setText(mRecipeList.get(position).getName()); return convertView; } static class ViewHolder { TextView recipeNameTv; } }
对应的grid_item_recipe.xml布局(放在res/layout下):
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:padding="8dp"> <TextView android:id="@+id/tv_recipe_name" android:layout_width="100dp" android:layout_height="100dp" android:gravity="center" android:background="#f0f0f0" android:textSize="14sp"/> </LinearLayout>
4. 实现RecyclerView的适配器
接下来写RecyclerView的适配器,每个Item嵌套一个GridView:
public class RecyclerViewWithGridAdapter extends RecyclerView.Adapter<RecyclerViewWithGridAdapter.ViewHolder> { private Context mContext; private List<List<String>> mRecipeGroups; // 把菜谱分成多组,每组对应一个GridView的数据 // 用实体类的话改成List<List<Recipe>> public RecyclerViewWithGridAdapter(Context context, List<List<String>> recipeGroups) { this.mContext = context; this.mRecipeGroups = recipeGroups; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_item_with_grid, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { // 给当前Item的GridView设置适配器 GridRecipeAdapter gridAdapter = new GridRecipeAdapter(mContext, mRecipeGroups.get(position)); holder.gridView.setAdapter(gridAdapter); // 给GridView添加点击事件 holder.gridView.setOnItemClickListener((parent, view, gridPosition, id) -> { String selectedRecipe = mRecipeGroups.get(position).get(gridPosition); Toast.makeText(mContext, "你选中了:" + selectedRecipe, Toast.LENGTH_SHORT).show(); // 这里可跳转到菜谱详情页 }); } @Override public int getItemCount() { return mRecipeGroups.size(); } static class ViewHolder extends RecyclerView.ViewHolder { GridView gridView; public ViewHolder(@NonNull View itemView) { super(itemView); gridView = itemView.findViewById(R.id.grid_view); // 设置GridView列数 gridView.setNumColumns(3); } } }
对应的recycler_item_with_grid.xml布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <!-- 可添加分组标题,比如“家常菜组” --> <TextView android:id="@+id/tv_group_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="菜谱组" android:textSize="18sp" android:textStyle="bold" android:marginBottom="8dp"/> <GridView android:id="@+id/grid_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:horizontalSpacing="8dp" android:verticalSpacing="8dp"/> </LinearLayout>
5. 在Activity/Fragment中整合所有逻辑
最后在页面里,从数据库取数据、分组,再绑定到RecyclerView:
public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private RecyclerViewWithGridAdapter mAdapter; private MyDBHandler mDbHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = findViewById(R.id.recycler_view); mDbHandler = new MyDBHandler(this); // 1. 从数据库获取所有菜谱 List<String> allRecipes = mDbHandler.getAllRecipeNames(); // 2. 把菜谱分组(比如每组6个,可按需调整) List<List<String>> recipeGroups = new ArrayList<>(); int groupSize = 6; for (int i = 0; i < allRecipes.size(); i += groupSize) { int end = Math.min(i + groupSize, allRecipes.size()); recipeGroups.add(allRecipes.subList(i, end)); } // 3. 配置RecyclerView mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mAdapter = new RecyclerViewWithGridAdapter(this, recipeGroups); mRecyclerView.setAdapter(mAdapter); } }
对应的activity_main.xml布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
额外注意事项
- 如果不需要分组展示菜谱,直接用RecyclerView的
GridLayoutManager就能实现GridView效果,不需要嵌套GridView,性能会更好。 - 数据库操作建议放在子线程(比如用Coroutine或AsyncTask),避免阻塞主线程导致卡顿。
- 若数据量较大,确保适配器的ViewHolder复用逻辑正确,避免内存泄漏。
内容的提问来源于stack exchange,提问作者wilrus
相关产品推荐
相关产品推荐

