Android SQLite查询封装ArrayList时结果全为最后一行重复
问题根因
你在 getFiles() 方法中只在循环外初始化了一次 FileUploaded 对象,遍历 Cursor 时反复修改同一个对象的属性,再把这个对象的引用反复添加到 ArrayList 里。
Java 的 ArrayList 存储的是对象的内存引用,不是对象本身的深拷贝。最终列表里所有元素都指向同一个内存地址的实体,属性值自然会被最后一次循环读取的行数据覆盖,导致所有返回结果都和最后一行一模一样。
修复代码
把实体对象的实例化逻辑移到循环内部,每读取一行数据就创建一个新的 FileUploaded 实例,再添加到列表即可,修改后的完整查询方法如下:
public ArrayList<FileUploaded> getFiles(){ SQLiteDatabase db = this.getReadableDatabase(); ArrayList<FileUploaded> results = new ArrayList<>(); Cursor cs = db.rawQuery("SELECT * FROM files", null); // 直接用moveToNext做循环判断,逻辑更简洁 while (cs.moveToNext()) { // 每一行数据对应一个新的实体实例 FileUploaded file = new FileUploaded(); file.setId(cs.getInt(cs.getColumnIndexOrThrow("id"))); file.setTitle(cs.getString(cs.getColumnIndexOrThrow("title"))); file.setImage(BitmapUtility.getImage(cs.getBlob(cs.getColumnIndexOrThrow("image")))); results.add(file); } // 关闭Cursor释放数据库资源 cs.close(); return results; }
优化提示
- 用
getColumnIndexOrThrow()代替原代码的getColumnIndex(),如果字段名写错会直接抛出明确的异常,比字段不存在时返回-1的隐形bug更容易排查。 - 遍历 Cursor 时不需要单独先调用
moveToFirst()再判断是否到末尾,直接用moveToNext()做循环条件可以覆盖空 Cursor、非空 Cursor 的所有场景,逻辑更不容易出错。 - 操作完成后必须关闭 Cursor,避免数据库连接相关的内存泄漏。
内容的提问来源于stack exchange,提问作者Ahmed Laggoun
相关产品推荐
相关产品推荐

