DBHelper.getWirtableDatabse 抛出空异常

Posted

技术标签:

【中文标题】DBHelper.getWirtableDatabse 抛出空异常【英文标题】:DBHelper.getWirtableDatabse throws null exception 【发布时间】:2017-09-02 02:22:53 【问题描述】:

我正在尝试为用户编写自己的内容提供程序。当我尝试验证用户是否存在时,当 DBHelper 尝试创建数据库时,它会抛出一个空异常。

这里是内容提供者:

public class MyUserProvider extends ContentProvider 
    private UserDBHelper db;

    private static final int USERS = 10;
    private static final int USER_ID = 20;

    private static final String AUTHORITY =
            "net.ifo420.ritc.agenda.userprovider";

    private static final String BASE_PATH = "users";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
                                        + "/" + BASE_PATH);

    public static final String CONTENT_TYPE =
            ContentResolver.CURSOR_DIR_BASE_TYPE + "/users";

    public static final String CONTENT_ITEM_TYPE =
            ContentResolver.CURSOR_ITEM_BASE_TYPE + "/user";

    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static 
        uriMatcher.addURI(AUTHORITY, BASE_PATH, USERS);
        uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", USER_ID);
    

    public MyUserProvider() 
    

    @Override
    public boolean onCreate() 
        db = new UserDBHelper(getContext());
        return false;
    

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) 
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

        checkColumns(projection);

        queryBuilder.setTables(UserTable.TABLE);

        int uriType = uriMatcher.match(uri);
        switch (uriType) 
            case USERS:
                break;
            case USER_ID:
                queryBuilder.appendWhere(UserTable.COLUMN_ID + " = " + uri.getLastPathSegment());
                break;
            default:
                throw new IllegalArgumentException("Uknown uri " + uri);
        
        SQLiteDatabase db1 = db.getReadableDatabase();
        Cursor cursor = queryBuilder.query(db1, projection, selection, selectionArgs,
                null, null, sortOrder);

        cursor.setNotificationUri(getContext().getContentResolver(), uri);

        return cursor;
    

    @Override
    public String getType(Uri uri) 
        return null;
    

    @Override
    public Uri insert(Uri uri, ContentValues values) 
        int uriType = uriMatcher.match(uri);
        SQLiteDatabase database = db.getReadableDatabase();
        long id = 0;
        switch (uriType) 
            case USERS:
                id = database.insert(UserTable.TABLE, null, values);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        
        getContext().getContentResolver().notifyChange(uri, null);
        return Uri.parse(BASE_PATH + "/" + id);
    

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) 
        int uriType = uriMatcher.match(uri);
        SQLiteDatabase sqLiteDatabase = db.getReadableDatabase();
        int rowsDeleted = 0;
        switch (uriType) 
            case USERS:
                rowsDeleted = sqLiteDatabase.delete(UserTable.TABLE, selection,
                        selectionArgs);
                break;
            case USER_ID:
                String id = uri.getLastPathSegment();
                if(TextUtils.isEmpty(selection)) 
                    rowsDeleted = sqLiteDatabase.delete(UserTable.TABLE,
                            UserTable.COLUMN_ID + " = " + id, null);
                 else 
                    rowsDeleted = sqLiteDatabase.delete(UserTable.TABLE,
                            UserTable.COLUMN_ID + " = " + id + " and " +
                    selection, selectionArgs);
                
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsDeleted;
    

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) 
        int uriType = uriMatcher.match(uri);
        SQLiteDatabase sqLiteDatabase = db.getReadableDatabase();
        int rowsUpdated = 0;
        switch (uriType) 
            case USERS:
                rowsUpdated = sqLiteDatabase.update(UserTable.TABLE,
                        values,
                        selection,
                        selectionArgs);
                break;
            case USER_ID:
                String id = uri.getLastPathSegment();
                if (TextUtils.isEmpty(selection)) 
                    rowsUpdated = sqLiteDatabase.update(UserTable.TABLE,
                            values,
                            UserTable.COLUMN_ID + "=" + id,
                            null);
                 else 
                    rowsUpdated = sqLiteDatabase.update(UserTable.TABLE,
                            values,
                            UserTable.COLUMN_ID + "=" + id
                                    + " and "
                                    + selection,
                            selectionArgs);
                
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsUpdated;
    

    private void checkColumns(String[] projection) 
        String[] available = UserTable.COLUMN_USERNAME, UserTable.COLUMN_PASSWORD,
                            UserTable.COLUMN_ID;

        if (projection != null) 

            HashSet<String> requestedColumns =
                    new HashSet<String>(Arrays.asList(projection));
            HashSet<String> availableColumns =
                    new HashSet<String>(Arrays.asList(available));

            if (!availableColumns.containsAll(requestedColumns)) 
                throw new IllegalArgumentException("Unknown columns in projection");
            
        
    

这是我的 DBHelper

public class UserDBHelper extends SQLiteOpenHelper 
    private static final String DB_NAME = "agenda.db";
    private static final int DB_VERSION = 1;

    public UserDBHelper (Context context) 
        super(context, DB_NAME, null, DB_VERSION);
    

    @Override
    public void onCreate(SQLiteDatabase db) 
        UserTable.onCreate(db);
    

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
        UserTable.onUpgrade(db, oldVersion, newVersion);
    

Here is the sample code I am using to verify if the user exists (sorry a bit is in french):

        public void onClick(View view) 
        switch (view.getId()) 
            case R.id.boutonLogin:
                if (userExists()) 
                    Toast.makeText(this, "L'utilisateur existe.", Toast.LENGTH_SHORT).show();
                 else 
                    Toast.makeText(this, "L'utilisateur n'existe pas.", Toast.LENGTH_SHORT).show();
                
    

    private boolean userExists() 
        String username = nomUtilisateur.getText().toString();
        String password = motPasse.getText().toString();

        Cursor users = userProvider.query(MyUserProvider.CONTENT_URI,
                null,
                " WHERE username = " + nomUtilisateur.getText().toString() +
                " AND password = " + motPasse.getText().toString(), null, null);

        if (users.getCount() != 0) 
            return true;
         else 
            return false;
        

这是 logcat 给我的:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite.SQLiteDatabase net.info420.ritc.agendacegep.UserDBHelper.getReadableDatabase()' on a null object reference
  at net.info420.ritc.agendacegep.MyUserProvider.query(MyUserProvider.java:70)
  at net.info420.ritc.agendacegep.LoginActivity.utilisateurExiste(LoginActivity.java:69)
  at net.info420.ritc.agendacegep.LoginActivity.onClick(LoginActivity.java:57)
  at android.view.View.performClick(View.java:5610)
  at android.view.View$PerformClick.run(View.java:22260)
  at android.os.Handler.handleCallback(Handler.java:751)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:154)
  at android.app.ActivityThread.main(ActivityThread.java:6077)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

【问题讨论】:

onCreate中尝试return true 还是不行 【参考方案1】:

您不能直接实例化和调用 ContentProvider - 您必须通过内容解析器。否则,它不会经历提供者的生命周期,并且不会调用 onCreate。

【讨论】:

当我尝试获取游标返回的结果数时,它现在会引发异常。它说它是空的,当我尝试查看数据库时,它没有被创建。 好的,所以我一直在运行一些带有标签的测试,我注意到在我的应用程序开始时调用了 onCreate 方法,而不是在我想使用 getWritableDatabase() 时调用。而且query()方法在我调用的时候也不会被调用,所以游标为空是正常的,但是数据库仍然没有创建。 得到了我的答案,部分问题是你提到的。谢谢!【参考方案2】:

嗯,我有自己的答案。是的,我无法实例化我的 ContentProvider,但不仅如此。我更改了代码并意识到我只是没有真正理解查询中的 selection 和 selectionArgs 参数。

所以它来自:

private boolean userExists() 
    String username = nomUtilisateur.getText().toString();
    String password = motPasse.getText().toString();

    Cursor users = userProvider.query(MyUserProvider.CONTENT_URI,
            null,
            " WHERE username = " + nomUtilisateur.getText().toString() +
            " AND password = " + motPasse.getText().toString(), null, null);

    if (users.getCount() != 0) 
        return true;
     else 
        return false;
    

收件人:

private boolean userExists() 
    String username = nomUtilisateur.getText().toString();
    String password = motPasse.getText().toString();
    String[] selection = username, password;

    Cursor users = getApplicationContext().getContentResolver().query
            (Agenda.UserEntry.CONTENT_URI,
            null,
            "username = ? AND password = ?", selection, null);

    if (users.getCount() != 0) 
        return true;
     else 
        return false;
    

所以,光标为空,因为我没有进行正确的查询,这就是我的数据库没有创建的原因:因为我在代码的末尾不需要它。

【讨论】:

以上是关于DBHelper.getWirtableDatabse 抛出空异常的主要内容,如果未能解决你的问题,请参考以下文章