【问题标题】:Why is DBHelper not closed in the Android notepad tutorial?为什么Android记事本教程中没有关闭DBHelper?
【发布时间】:2012-04-03 15:14:25
【问题描述】:

我目前正在编写我的第一个 Android 应用程序,并且我的大部分知识都基于 Android 记事本教程:

http://developer.android.com/resources/tutorials/notepad/notepad-ex3.html

在我的应用程序中,我在一个 Activity 中使用多个 DBHelper,并不是每个 Cursor 都由带有 startManagingCursor() 的 Activity 管理。

我了解到每个数据库连接都必须正确打开和关闭:

SQLiteOpenHelper.open();
Cursor.open();
//use cursor
Cursor.close();
SQLiteOpenHelper.close();

据我所知 startManagingCursor() 为您工作。但是 startManagingCursor() 是否也打开和关闭 SQLiteOpenHelper?

Android 记事本教程使用 startManagingCursor() 但 DBHelper 从未关闭。为什么 SQLiteOpenHelper 永远不会关闭?

编辑:

这是我当前的代码。它使用一个名为 mDriverDbHelper 的 SQLiteOpenHelper。此代码是从教程中采用的:

私有 DriverDbAdapter mDriverDbHelper;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.bus_selectuser);
    mDbHelper = new DbAdapter(this);
    mDbHelper.open();
    mDbHelper.close();
    mDriverDbHelper = new DriverDbAdapter(this);
    Log.w("BuerBusActivity", "opening DB connection via DbHelber now");

    mDriverDbHelper.open();
    fillData();

    //request the screen to stay on
    this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}

@Override
public void onRestart() {
    super.onRestart();

    Log.v(TAG, "onRestart");
}

@Override
public void onStart() {
    super.onStart();
    mDriverDbHelper.open();
    Log.v(TAG, "onStart");
}

@Override
public void onResume() {
    super.onResume();
    Log.v(TAG, "onResume");
}

@Override
public void onPause() {
    Log.v(TAG, "onPause");
    super.onPause();
}

@Override
public void onStop() {
    mDriverDbHelper.close();
    Log.v(TAG, "onStop");
    super.onStop();
}

此代码示例确实有效,但我不明白为什么。我在 onCreate 和 onStart 中调用了 mDriverDBHelper.open() 两次。

我尝试将 open() 和 close() 调用放在 onPause 和 onResume 中,但这会导致错误:

Cursor: invalid statement in fillWindow()

有谁知道为什么它必须是 onStart 和 onStop 而不是 onPause 和 onResume?

最终答案

本教程缺少 close() 方法调用。结合活动生命周期使用 open 和 close 的一般规则是:

在活动生命周期方法中打开 SQLiteOpenHelper 后,您应该在相应的对应生命周期方法中关闭它。

@Override
public void onCreate() {
    ....
    //open SQLiteOpenHelper
    onCreateHelper.open();
}

@Override
public void onStart() {
    ....
    //open SQLiteOpenHelper
    onStartHelper.open();
}

@Override
public void onResume() {
    ....
    //open SQLiteOpenHelper
    onResumeHelper.open();
}

@Override
public void onPause() {
    ....
    //close SQLiteOpenHelper
    onResumeHelper.close();
}

@Override
public void onStop() {
    ....
    //close SQLiteOpenHelper
    onStartHelper.close();
}

@Override
public void onDestroy() {
    ....
    //close SQLiteOpenHelper
    onCreateHelper.close();
}

在 Android NotePad 教程中,缺少 onDestroy() 方法,应该关闭 mDbHelper。

【问题讨论】:

    标签: android sqliteopenhelper


    【解决方案1】:

    根据startManagingCursor 文档,它只处理游标。所以我相信它不会对数据库连接做任何事情,因为它将来可能需要重新查询数据。

    来自 Android 开发者的网站:

    此方法允许 Activity 负责管理给定的 基于活动生命周期的光标生命周期。那是, 当活动停止时,它会自动调用 deactivate() 在给定的光标上,当它稍后重新启动时,它将调用 requery() 为您服务。当活动被销毁时,所有托管游标 会自动关闭。

    关于在 android notepad 教程中关闭数据库连接,我认为他们错过了在示例代码中关闭它。所以没什么大不了的:)

    【讨论】:

    • 好吧,我就是这么想的 :-) 我应该在哪里关闭 SQLiteOpenHelper?我是否将其放在 onStop() 方法中?我是否还必须在 onRestart() 中重新打开它?
    • 是的,在 onStart 或 onResume 中打开 db 连接,在 onStop 或 onPause 中分别关闭
    【解决方案2】:

    不管怎样,示例代码也没有处理用户点击设备的返回按钮的真实可能性。这可能会导致空指针通过 bundle extras 传递。为了防止示例崩溃,您可以在 super 调用之后将 try / catch 块包裹在所有内容周围,如下所示:

     @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
            try {
                  Bundle extras = intent.getExtras();
    
                  switch(requestCode) {
                  case ACTIVITY_CREATE:
                         String title = extras.getString(NotesDbAdapter.KEY_TITLE);  
                                  // ^^^ LATER down goes KA-BOOM !
                   // etc ... as in sample
                  } // end switch stmt
             } catch (Exception e ) {
              Log.d ( "onActivityResult caught exception: ", e.toString() ) ;
             } // end try / catch
        // ...   
    

    就像 C/C++ 似乎 null 东西是 Java 中最常见的错误......

    【讨论】:

      【解决方案3】:

      永远不要关闭 DbHelper 旨在永远保持打开状态。

      并且不要关闭getReadableDatabase()和getWritableDatabase()的结果,即使是最优条件下的同一个对象。

      查看源代码,连程序员都不喜欢:

      private SQLiteDatabase getDatabaseLocked(boolean writable) {
          if (mDatabase != null) {
              if (!mDatabase.isOpen()) {
                  // Darn!  The user closed the database by calling mDatabase.close().
                  mDatabase = null;
              } else if (!writable || !mDatabase.isReadOnly()) {
                  // The database is already open for business.
                  return mDatabase;
              }
          }
      ...
      }
      

      为了稳定和加快使用交易,请检查: http://tech.vg.no/2011/04/04/speeding-up-sqlite-insert-operations/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-05
        • 2010-11-22
        • 2010-10-04
        • 2012-11-17
        • 2023-03-09
        • 2011-08-10
        • 1970-01-01
        • 2012-02-11
        相关资源
        最近更新 更多