Udacity热门电影项目:SQLite数据无法持久化问题求助
排查收藏数据无法持久化的常见问题
从你描述的情况来看,应用重启后收藏数据丢失,大概率是数据没有真正写入到SQLite数据库(毕竟Content Provider底层通常依赖SQLite),或者读取数据的逻辑存在疏漏。下面是几个最容易踩坑的点,你可以逐一排查:
1. 收藏操作时是否正确调用了ContentResolver的写入方法?
很多开发者会误以为调用了Content Provider的方法就完成了存储,但如果你的insert/update实现有问题,数据根本没落地:
- 有没有在Content Provider的
insert方法里真正执行SQLiteDatabase.insert(),并且返回了正确的Uri?如果返回null,说明插入失败; - 传递的
ContentValues是不是为空,或者字段名和数据库表的列名不匹配?比如表列叫movie_title,你却存了title,数据自然写不进去; - 是不是直接操作了SQLite数据库,但没通过
getContentResolver().insert(...)走Content Provider的流程?这样数据不会被Content Provider感知,后续读取也可能出问题。
给你贴个正确的收藏写入示例:
// 收藏影片时的核心代码 ContentValues values = new ContentValues(); values.put(MovieContract.MovieEntry.COLUMN_MOVIE_ID, movie.getId()); values.put(MovieContract.MovieEntry.COLUMN_TITLE, movie.getTitle()); values.put(MovieContract.MovieEntry.COLUMN_POSTER_PATH, movie.getPosterPath()); // 其他必填字段... Uri insertedUri = getContentResolver().insert(MovieContract.MovieEntry.CONTENT_URI, values); // 可以通过Uri是否为null判断写入是否成功 if (insertedUri == null) { // 这里可以加个日志,确认写入失败了 Log.e("MainActivity", "收藏影片失败"); }
2. Content Provider的query方法是否正确返回所有收藏数据?
用CursorLoader加载数据时,如果query方法逻辑错了,就算数据库里有数据也读不出来:
- 是不是在query里返回了空Cursor,或者错误地加了过滤条件,导致只查了部分数据?
- 数据库表的字段和query中指定的投影字段是不是不匹配?比如投影里要了
poster_path,但表列叫poster_url,Cursor里自然没数据。
检查你的Content Provider的query实现,确保它正确从SQLite中读取所有收藏:
@Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = mDbHelper.getReadableDatabase(); Cursor cursor; int match = sUriMatcher.match(uri); switch (match) { case MOVIES: // 查询整个收藏表的数据 cursor = db.query(MovieContract.MovieEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); break; // 其他单条数据查询的case... default: throw new IllegalArgumentException("无法查询未知URI: " + uri); } // 别忘了设置通知Uri,这样数据变化时CursorLoader能自动更新 cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; }
3. SQLite数据库的表创建/版本更新是否有问题?
如果你的SQLiteOpenHelper没正确创建收藏表,或者版本更新时误删了表,数据根本没地方存:
- 创建表的SQL语句是不是写错了?比如少了主键、字段名拼写错误,或者忘了加
NOT NULL约束导致数据插入失败; - 数据库版本号更新后,
onUpgrade方法是不是没处理好表迁移?比如直接删表重建,导致旧数据丢失。
给你个正确的表创建示例:
private static final String SQL_CREATE_MOVIES_TABLE = "CREATE TABLE " + MovieContract.MovieEntry.TABLE_NAME + " (" + MovieContract.MovieEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + MovieContract.MovieEntry.COLUMN_MOVIE_ID + " INTEGER UNIQUE NOT NULL," + // 用电影ID做唯一约束,避免重复收藏 MovieContract.MovieEntry.COLUMN_TITLE + " TEXT NOT NULL," + MovieContract.MovieEntry.COLUMN_POSTER_PATH + " TEXT NOT NULL" + ");"; @Override public void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE_MOVIES_TABLE); }
4. CursorLoader初始化时是否监听了正确的Uri?
如果你的CursorLoader加载的是单条影片的Uri,而不是整个收藏表的Uri,自然读不到所有收藏数据:
// 正确初始化CursorLoader的方式 getSupportLoaderManager().initLoader(MOVIE_FAV_LOADER_ID, null, this); @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { String[] projection = { MovieContract.MovieEntry._ID, MovieContract.MovieEntry.COLUMN_TITLE, MovieContract.MovieEntry.COLUMN_POSTER_PATH }; // 这里要传对应整个收藏表的CONTENT_URI,而不是单条数据的Uri return new CursorLoader(this, MovieContract.MovieEntry.CONTENT_URI, projection, null, null, null); }
5. 验证数据是否真的写入了数据库
你可以用Android Studio的Device File Explorer找到应用的数据库文件(路径是data/data/你的包名/databases/下的.db文件),导出后用SQLite工具打开,直接查看收藏表有没有数据。如果表中没数据,说明写入逻辑有问题;如果表中有数据但加载不出来,就是读取逻辑的问题。
如果以上排查都没找到问题,建议你贴出Main Activity中收藏操作的代码,以及Content Provider的insert/query核心实现,这样能更精准地定位问题。
内容的提问来源于stack exchange,提问作者sandy
相关产品推荐
相关产品推荐

