You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:58:56