使用 Android 的游标从数据库实现方法 getXXX 的最佳实践

Best practice to implement method getXXX from db using cursor for Android

例如下面的示例代码。我们需要关闭游标吗?我们最好使用 try/catch/finally 而不是 if() 吗?

public int getCount() {


    final Cursor countCursor = contentResolver.query(
            AnalyticContract.CONTENT_URI,
            new String[] {"count(*) AS count"},
            null,
            null,
            null);
    if (countCursor == null) {
        return 0;
    }

    countCursor.moveToFirst();
    final int count = countCursor.getInt(0);
    return count;
}

try-with-resources语句是声明一个或多个资源的try语句。资源是一个对象,在程序使用完它后必须关闭。 try-with-resources 语句确保在语句结束时关闭每个资源。任何实现 java.lang.AutoCloseable 的对象,包括所有实现 java.io.Closeable 的对象,都可以用作资源。 https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

我认为答案主要是基于意见的。我猜这取决于编码人员的偏好和环境。

我一直更喜欢 if (cursor != null) 方法,反之亦然。除非发生了真正壮观的事情;这将由 throws Exception 处理,我会在任何我想要 reader/reviewer 的地方使用 if-else 检查来查看哪些部分是 真正的 异常,哪些是出现不同的 possible/valid 情景。


这给我们带来了 Curosr 和应用空值检查的当前问题。

AFAIK(因为大多数 CursorSQLiteDatabase 相关)如果查询本身是有效,除非在无效查询的情况下这是一个真正的异常,你应该得到一个异常。

所以我认为最好的方法是使用您的示例

public int getCount() throws Exception {

    Cursor countCursor;
    try {
        countCursor = contentResolver.query(
                AnalyticContract.CONTENT_URI,
                new String[] {"count(*) AS count"},
                null,
                null,
                null);

        countCursor.moveToFirst();
        return countCursor.getInt(0);
    }
    finally {
        cursor.close();
    }
}

或者在方法本身内捕获和处理异常的变体。


现在回答你的第二个问题,你是否应该 close() a Cursor:你应该总是关闭 a Cursor。当你不需要它的时候。如果您深入研究任何 Cursor.close() 方法实现。由于 Curosr 是一个接口,如果 SQLite 是由 SQLiteCursor 实现的,您会注意到此方法释放了它持有的所有分配。

我更喜欢做一个数据库助手class,这样数据库访问就变得容易多了。数据库助手示例 Class -

public class DatabaseHelperClass extends SQLiteOpenHelper {

public DatabaseHelperClass(Context context)
{
    super(context,"hakeem.db",null,1);
}

//Tables
@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL("Your SQL Query to create a table");
   }


//Delete Tables
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("drop table table_name if exists");
    onCreate(db);
}

//Insertion of data into tables
long insertData(Various Parameters you like to pass for insertion)
{
    SQLiteDatabase db=getWritableDatabase();
    ContentValues values=new ContentValues();

values.put("col_name1",value);
values.put("col_name2",value);
values.put("col_name3",value);
values.put("col_name4",value);

    return db.insert("signup_details",null,values);
}

//Delete record
public int deleteData(int id)
{
    SQLiteDatabase sb=getWritableDatabase();
    return sb.delete("hospital_details","id="+id,null);
}


//Update data in table
int updateData(Parameters you want to pass for update. Make sure you include a primary key)
{
    ContentValues values=new ContentValues();

     values.put("col_name1",value);
     values.put("col_name2",value);
      values.put("col_name3",value); 
      values.put("col_name4",value);

    return getWritableDatabase().update("signup_details",values,"id="+id,null);
}



//Read data from tables
Cursor getSigninDetails() { return getWritableDatabase().rawQuery("select  * from table_name",null); }
}

并从数据库访问结果-

 private void getDataFromDatabase() {

    Cursor cursor = db.getUserData();

    if (cursor.moveToFirst()) {
        do {

            var_name1= cursor.getString(0);
            var_name2= cursor.getString(1);
            var_name3= cursor.getString(2);
            var_name4= cursor.getString(3);

        } while (cursor.moveToNext());
    }
cursor.close();

}