多CursorAdapter适配不同Fragment仅一个生效,RecipeCursorAdapter报错求助
从你的报错日志和代码来看,核心问题是**RecipeCursorAdapter拿到的Cursor并不属于recipes表**——日志里getColumnIndex(RecipeEntry.COLUMN_RECIPE_SERVINGS)返回了-1,说明这个Cursor里根本没有这个列,结合你怀疑的点,大概率是给RecipeCursorAdapter传入了查询store表得到的Cursor,导致访问不存在的列抛出异常。
下面是一步步的排查和解决方法:
1. 确认Cursor的来源是否正确
首先检查你创建RecipeCursorAdapter的地方(比如对应的RecipeFragment的Loader回调里),确保查询的是recipes表的Uri,而不是store表的:
比如在RecipeFragment的LoaderManager.LoaderCallbacks<Cursor>实现中,onCreateLoader方法应该是这样的:
@Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { // 只查询recipes表需要的列 String[] projection = { RecipeEntry._ID, RecipeEntry.COLUMN_RECIPE_NAME, RecipeEntry.COLUMN_RECIPE_TYPE, RecipeEntry.COLUMN_RECIPE_SERVINGS, RecipeEntry.COLUMN_RECIPE_VALUES }; // 必须使用RecipeEntry的CONTENT_URI,而不是StoreEntry的 return new CursorLoader(getContext(), RecipeEntry.CONTENT_URI, projection, null, null, null); }
如果这里误用了StoreEntry.CONTENT_URI,就会拿到store表的Cursor,自然找不到recipes表的列。
2. 检查ContentProvider的query逻辑
确认你的ContentProvider中,针对RecipeEntry.CONTENT_URI的查询,确实返回的是recipes表的数据:
@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) { // 确保RECIPES匹配的是RecipeEntry的Uri case RECIPES: cursor = db.query( RecipeEntry.TABLE_NAME, // 这里必须是recipes表的表名常量 projection, selection, selectionArgs, null, null, sortOrder); break; case STORES: cursor = db.query(StoreEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); break; // 其他匹配分支... default: throw new IllegalArgumentException("无法查询未知URI: " + uri); } cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; }
同时要确认UriMatcher的规则是正确的,比如:
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { sUriMatcher.addURI(CONTENT_AUTHORITY, RecipeEntry.PATH_RECIPES, RECIPES); sUriMatcher.addURI(CONTENT_AUTHORITY, StoreEntry.PATH_STORES, STORES); }
保证Recipe的Uri能正确匹配到RECIPES分支,查询正确的表。
3. 验证列名常量的正确性
检查RecipeEntry里的列名常量是否和数据库创建时的列名完全一致,比如:
public static final String COLUMN_RECIPE_SERVINGS = "recipe_servings";
要确保这个字符串和你创建recipes表时写的列名完全相同,没有拼写错误(比如大小写、多/少字母)。
4. 额外调试技巧
如果还是不确定问题,可以在RecipeCursorAdapter的bindView方法里打印Cursor的所有列名,直接验证Cursor属于哪个表:
// 在bindView开头添加这段代码 for (int i = 0; i < cursor.getColumnCount(); i++) { Log.e(LOG_TAG, "当前Cursor的列名: " + cursor.getColumnName(i)); }
如果打印出来的是store表的列(比如product_name、product_price等),那就实锤是传错了Cursor,回到步骤1和2修正即可。
按照上面的步骤排查后,RecipeCursorAdapter应该能正确访问recipes表的数据,和PlatformCursorAdapter各自正常工作。
内容的提问来源于stack exchange,提问作者Wissam

