Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/188.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android-db中对SQLite数据库的并发访问已关闭_Android_Sqlite_Sqliteopenhelper_Getwritabledatabase - Fatal编程技术网

Android-db中对SQLite数据库的并发访问已关闭

Android-db中对SQLite数据库的并发访问已关闭,android,sqlite,sqliteopenhelper,getwritabledatabase,Android,Sqlite,Sqliteopenhelper,Getwritabledatabase,我读了很多关于这个主题的文章,但是没有人能回答我的问题 我从并发线程访问数据库,我的SQLiteOpenHelper实现了singleton的设计模式,所以我的应用程序只有一个实例 我使用如下代码访问我的数据库: SQLiteDatabase db = DatabaseHelper.getInstance().getWritableDatabase(); ... Do some update in the DB ... db.close(); 我不明白为什么我仍然得到“db read

我读了很多关于这个主题的文章,但是没有人能回答我的问题

我从并发线程访问数据库,我的SQLiteOpenHelper实现了singleton的设计模式,所以我的应用程序只有一个实例

我使用如下代码访问我的数据库:

 SQLiteDatabase db = DatabaseHelper.getInstance().getWritableDatabase();
 ...
 Do some update in the DB
 ...
 db.close();
我不明白为什么我仍然得到“db ready closed”错误,getWritableDatabase()方法不应该在调用close()之前锁定数据库吗?来自其他线程的其他getWritableDatabase()调用应该等待数据库关闭吗?是这样还是我错过了什么?如果你打电话 DatabaseHelper.getInstance().getWritableDatabase()
在您的线程中,我建议您在启动线程之前管理它。在主程序中打开数据库,调用线程。线程终止后,您将关闭主程序中的数据库。

扩展elhadi的回答,在跨多个异步任务打开和关闭数据库连接时,我遇到了类似的问题。从我当时的调查来看,很明显没有必要经常打开和关闭db连接。我最终采用的方法是对
应用程序进行子分类,并在
onCreate
期间执行单个db open,在terminate
期间执行单个db close。然后,我设置了一个静态getter来检索已经打开的
SQLiteDatabase
对象。不是DI(依赖注入)友好的,但Android还不能真正做到这一点

像这样的东西

    public class MainApplication extends Application {
          private static SQLiteDatabase database;

          /**
           * Called when the application is starting, before any other 
           * application objects have been created. Implementations 
           * should be as quick as possible...
           */
          @Override
          public void onCreate() {
          super.onCreate();
          try {
           database = SQLiteDatabase.openDatabase("/data/data/<yourdbpath>", null, SQLiteDatabase.OPEN_READWRITE);
          } catch (SQLiteException e) {
            // Our app fires an event spawning the db creation task...
           }
         }


          /**
           * Called when the application is stopping. There are no more 
           * application objects running and the process will exit.
           * <p>
           * Note: never depend on this method being called; in many 
           * cases an unneeded application process will simply be killed 
           * by the kernel without executing any application code...
           * <p>
           */
          @Override
          public void onTerminate() {
            super.onTerminate();
            if (database != null && database.isOpen()) {
              database.close();
            }
          }


          /**
           * @return an open database.
           */
          public static SQLiteDatabase getOpenDatabase() {
            return database;
          }
    }
    /**
    * Listener waiting for the application to finish
    * creating the database.
    * <p>
    * Once this has been completed the database is ready for I/O.
    * </p>
    *
    * @author David C Branton
    */
      public class OpenDatabaseReceiver extends BroadcastReceiver {
        public static final String BROADCAST_DATABASE_READY = "oceanlife.core.MainApplication$OpenDatabaseReceiver.BROADCAST_DATABASE_READY";

        /**
         * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
         */
        @Override
        public void onReceive(final Context context, final Intent intent) {
          Log.i(CreatedDatabaseReceiver.class.getSimpleName(), String.format("Received filter event, '%s'", intent.getAction()));
          database = SQLiteDatabase.openDatabase("/data/data/<your db path>", null, SQLiteDatabase.OPEN_READWRITE);
          unregisterReceiver(openDatabaseReceiver);

          // Broadcast event indicating that the creation process has completed.
          final Intent databaseReady = new Intent();
          databaseReady.setAction(BROADCAST_DATABASE_READY);
          context.sendBroadcast(databaseReady);
        }
      }
因此,第一次安装的启动过程总结如下:

  • 类:MainApplication,角色-检查是否有数据库?
    • 是吗?数据库变量已初始化
    • 没有?已注册接收器(OpenDatabaseReceiver)
  • 类:MainActivity:应用程序的角色登录活动,并最初检查数据库变量是否为null。
    • 数据库
      是否为空?不添加执行I/O的片段,并在对话框中添加“创建应用程序数据库”或类似内容
    • 数据库
      不为空?执行主应用程序执行流,添加db支持的列表等
  • 类:DatabaseCreationDialogFragment:role-生成异步任务以创建数据库。
    • 在创建数据库时注册新的侦听接收器
    • 在收集“我已经创建了数据库”消息时,会触发另一个事件(来自接收者),通知应用程序打开数据库
  • 类:main应用程序:角色2-侦听“已创建数据库”消息。
    • 上面描述的接收器(
      OpenDatabaseReceiver
      )打开数据库并广播(通过另一个事件!)数据库已准备好使用
  • 类:MainActivity:角色2-拾取“数据库已准备就绪”消息,摆脱“我们正在创建数据库”对话框,继续在应用程序中显示数据/功能

  • 和平已恢复。

    是,我在每个线程中调用DatabaseHelper.getInstance().getWritableDatabase()。谢谢你的回答,我要试试这个。但是我的反射理论上正确吗?在您的解决方案中,我应该在启动线程之前调用getWritableDatabase()来启动数据库吗?我真的不知道它应该有什么帮助,因为我仍然需要在我的线程中调用getWritableDatabase(),对吗?如果您尝试这样做,请不要忘记使用新应用程序“name”的路径更新您的
    Manifest.xml
    。您好,我现在在数据库路径方面遇到一些问题。显然,它找不到DB,getOpenDatabase抛出NullPointerException。我是否可以使用DatabaseHelper.getInstance().getWritableDatabase()等替代openDatabase()(仅一次)?(重要的是)添加了Fr4nz的更多详细信息。读一读,画出一些东西。如果你想知道“长版本”的原因,我们最好在“聊天”中了解。这一切都是关于碎片的角色和责任,并告知用户发生了什么。感谢您的详细回答,我将尝试这个好的总结!(即使概述了一个有点愚蠢的设计——对话框也没有产生线程和接收者的业务)
        /**
        * Listener waiting for the application to finish
        * creating the database.
        * <p>
        * Once this has been completed the database is ready for I/O.
        * </p>
        *
        * @author David C Branton
        */
          public class OpenDatabaseReceiver extends BroadcastReceiver {
            public static final String BROADCAST_DATABASE_READY = "oceanlife.core.MainApplication$OpenDatabaseReceiver.BROADCAST_DATABASE_READY";
    
            /**
             * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
             */
            @Override
            public void onReceive(final Context context, final Intent intent) {
              Log.i(CreatedDatabaseReceiver.class.getSimpleName(), String.format("Received filter event, '%s'", intent.getAction()));
              database = SQLiteDatabase.openDatabase("/data/data/<your db path>", null, SQLiteDatabase.OPEN_READWRITE);
              unregisterReceiver(openDatabaseReceiver);
    
              // Broadcast event indicating that the creation process has completed.
              final Intent databaseReady = new Intent();
              databaseReady.setAction(BROADCAST_DATABASE_READY);
              context.sendBroadcast(databaseReady);
            }
          }