为什么我得到 "Attempt to invoke interface method 'int android.database.Cursor.getCount()' on a null object reference"?

Why am I getting "Attempt to invoke interface method 'int android.database.Cursor.getCount()' on a null object reference"?

所以我得到 Attempt to invoke interface method 'int android.database.Cursor.getCount()' on a null object reference 当试图进入我的 MovieDetailActivity 以查看带有收藏按钮的 MovieDetails 时。根据电影的状态(是否收藏),按钮应相应地更改其文本以将电影添加到收藏夹列表或将其从收藏夹列表中删除。 但是我得到的只是在尝试进入屏幕时崩溃。

screenshot from the Logs

这是我的 isMovieFavourited 方法:

public boolean isMovieFavourited(String id){
    mSelectionClause = FavouritesContract.FavouritesAdd.COLUMN_MOVIE_ID + " = ?";
    mSelectionArgs[0] = id;
    Cursor mCursor = getContentResolver().query(
            FavouritesContract.FavouritesAdd.CONTENT_URI,
            mProjection,
            mSelectionClause,
            mSelectionArgs,
            null);

    if(mCursor.getCount() <= 0){
        mCursor.close();
        mFavourites.setText(getString(R.string.add_to_favourites));
        return false;
    }
    mCursor.close();
    mFavourites.setText(getString(R.string.remove_from_favourites));
    return true;
}

这是我的 FavouritesContract class:

public class FavouritesContract {
public static final String AUTHORITY = "com.riceplant.popularmovies";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + AUTHORITY);
public static final String PATH_FAVOURITES = "favourites";

public static final class FavouritesAdd implements BaseColumns {
    public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()
            .appendPath(PATH_FAVOURITES)
            .build();

    public static final String TABLE_NAME = "favorites";

    public static final String COLUMN_MOVIE_ID = "movieId";
    public static final String COLUMN_MOVIE_NAME = "movieName";
    public static final String COLUMN_MOVIE_POSTER = "moviePoster";
    public static final String COLUMN_MOVIE_RATE = "movieRate";
    public static final String COLUMN_MOVIE_RELEASE = "movieRelease";
    public static final String COLUMN_MOVIE_OVERVIEW = "movieOverview";
}

}

编辑: 这是我的内容提供者 class:

public class FavouritesContentProvide 扩展了 ContentProvider{

    public static final int FAVOURITES = 700;
    public static final int FAVOURITES_WITH_ID = 701;
    private static final UriMatcher sUriMatcher = buildUriMatcher();

    private static UriMatcher buildUriMatcher() {
        UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(FavouritesContract.AUTHORITY, FavouritesContract.PATH_FAVOURITES, FAVOURITES);
        uriMatcher.addURI(FavouritesContract.AUTHORITY, FavouritesContract.PATH_FAVOURITES + "/#", FAVOURITES_WITH_ID);
        return uriMatcher;
    }

    private FavouritesDbHelper mFavouritesDbHelper;

    @Override
    public boolean onCreate() {
        Context context = getContext();
        mFavouritesDbHelper = new FavouritesDbHelper(context);
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        final SQLiteDatabase db = mFavouritesDbHelper.getReadableDatabase();
        int match = sUriMatcher.match(uri);
        Cursor returnCursor;

        switch (match){
            case FAVOURITES:
                returnCursor = db.query(TABLE_NAME,
                        projection,
                        selection,
                        selectionArgs,
                        null,
                        null,
                        sortOrder);
                break;

            case FAVOURITES_WITH_ID:
                String id = uri.getPathSegments().get(1);
                String mSelection = "_id=?";
                String[] mSelectionArgs = new String[]{id};

                returnCursor = db.query(TABLE_NAME,
                        projection,
                        mSelection,
                        mSelectionArgs,
                        null,
                        null,
                        sortOrder);
                break;

            default:
                throw new UnsupportedOperationException("Unknown uri: "+ uri);
        }
        returnCursor.setNotificationUri(getContext().getContentResolver(), uri);
        return returnCursor;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        int match = sUriMatcher.match(uri);

        switch (match){
            case FAVOURITES:
                return "vnd.android.cursor.dir" + "/" + FavouritesContract.AUTHORITY + "/" + FavouritesContract.PATH_FAVOURITES;
            case FAVOURITES_WITH_ID:
                return "vnd.android.cursor.item" + "/" + FavouritesContract.AUTHORITY + "/" + FavouritesContract.PATH_FAVOURITES;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        final SQLiteDatabase db = mFavouritesDbHelper.getWritableDatabase();
        int match = sUriMatcher.match(uri);
        Uri returnUri; //Uri to be returned

        switch (match){
            case FAVOURITES:
                long id = db.insert(TABLE_NAME, null, values);
                if (id > 0 ){
                    returnUri = ContentUris.withAppendedId(FavouritesContract.FavouritesAdd.CONTENT_URI, id);
                } else {
                    throw new android.database.SQLException("Failed to insert row into" + uri);
                }
                break;
            default:
                throw new UnsupportedOperationException("Unknow uri: " +uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return returnUri;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        final SQLiteDatabase db = mFavouritesDbHelper.getWritableDatabase();
        int match = sUriMatcher.match(uri);
        int favoritesDeleted;

        switch (match) {
            case FAVOURITES:
                favoritesDeleted = db.delete(TABLE_NAME, selection, selectionArgs);
                break;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }

        if (favoritesDeleted != 0){
            getContext().getContentResolver().notifyChange(uri,null);
        }
        return favoritesDeleted;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        int favoriteUpdated;
        int match = sUriMatcher.match(uri);

        switch (match){
            case FAVOURITES_WITH_ID:
                String id = uri.getPathSegments().get(1);
                favoriteUpdated = mFavouritesDbHelper.getWritableDatabase()
                        .update(TABLE_NAME, values, "_id=?", new String[]{id});
                break;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }

        if (favoriteUpdated != 0){
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return favoriteUpdated;
    }

}

这是 Dbhelper class:

public class FavouritesDbHelper extends SQLiteOpenHelper {

private static final String DATABASE_NAME = "favourites.db";
private static final int DATABASE_VERSION = 3;

public FavouritesDbHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
    final String SQL_CREATE_FAVOURITES_TABLE = "CREATE TABLE " +
            FavouritesAdd.TABLE_NAME + " (" +
            FavouritesAdd._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
            FavouritesAdd.COLUMN_MOVIE_ID + " INTEGER NOT NULL," +
            FavouritesAdd.COLUMN_MOVIE_NAME + " TEXT NOT NULL," +
            FavouritesAdd.COLUMN_MOVIE_POSTER + " TEXT NOT NULL," +
            FavouritesAdd.COLUMN_MOVIE_RATE + " TEXT NOT NULL," +
            FavouritesAdd.COLUMN_MOVIE_RELEASE + " TEXT NOT NULL," +
            FavouritesAdd.COLUMN_MOVIE_OVERVIEW + " TEXT NOT NULL" +
            "); ";
    sqLiteDatabase.execSQL(SQL_CREATE_FAVOURITES_TABLE);
}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
    sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + FavouritesAdd.TABLE_NAME);
    onCreate(sqLiteDatabase);
}

}

我对此很陌生,所以请不要犹豫,询问您是否需要更多代码示例或其他任何东西。

提前致谢!

有 3 种情况 ContentResolver.query 方法可以 return null(是的,它可以 return null):

  1. 无法获取 Uri 提供程序。
  2. 提供商查询return为空。
  3. 执行查询时发生 RemoteException。

(您可以在 ContentResolver.java 的 source 中自己查看)

鉴于您的代码 posted,

(2) 似乎不太可能。 (我瞥了一眼,似乎不可能有 null 结果 - 理论上 SQLiteDatabase.query() 永远不会 return null 即使它确实如此,你也会在 setNotificationUri 你没有调用。)

(3) 无法根据提供的信息发表评论 - 很可能意味着您的提供商可以通过网络或其他方式访问 link。

但是

(1) 值得研究 - 提供的 URI 是否实际定义了配置的提供程序。具体来说 - 您是否在清单文件中定义了 <provider> 元素 - 参考 here 。如果是这样,则将清单的那部分添加到您的 post。你成功地与提供者做了什么吗?如果是,那么可能特定的 URI 不太正确。