【问题标题】:Unable to prevent SQLiteConnection object leakage无法防止 SQLiteConnection 对象泄漏
【发布时间】:2020-10-20 02:14:18
【问题描述】:

在我的 Android 应用程序中,我有一些使用 SQLite 的数据库事务,但是尽管尝试了多种方法来防止泄漏,但我还是遇到了 SQLiteConnection 对象泄漏。我几乎尝试过互联网上的每一件事,比如关闭数据库、关闭游标或结束事务。以下是android studio中的警告。

数据库“/data/user/0/com.example.myapp/databases/myapp.dbnotes.db”的 SQLiteConnection 对象被泄露!请修复您的应用程序以正确结束正在进行的事务并在不再需要时关闭数据库。

有时通过关闭数据库或关闭我曾经得到错误的游标 - Attempt to reopen an already-closed object ....。我不是Android专业人士,我正在尝试自己学习,所以你能帮助我吗?我已经发布了以下代码:

  • 在 DBHelper 类中

      public class DBHelper extends SQLiteOpenHelper {
    
        ...
          public static DBHelper getInstance(Context ctx) {
    
          if (mInstance == null) {
            mInstance = new DBHelper(ctx.getApplicationContext());
           }
           return mInstance;
         }
    
         private DBHelper(Context context) {
           super(context, DB_NAME, null, 1);
           this.context = context;
           DB_PATH = context.getDatabasePath(DB_NAME).getPath();
        }
    
       ...
    
       private Cursor getData(String Query) {
          String myPath = DB_PATH + DB_NAME;
          Cursor c = null;
         try {
              db = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
              c = db.rawQuery(Query, null);
            } catch (Exception e) {
              e.printStackTrace();
             }
          return c;
         }
    
       private void dml(String Query) {
          String myPath = DB_PATH + DB_NAME;
          if (db == null)
            db = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
          try {
             db.execSQL(Query);
          } catch (Exception e) {
             e.printStackTrace();
          }
        }
    
    
    
    
      //Methods to perform different db transaction
    
      public void addToSubject(ItemSubject itemSubject) {
       if (checkSuggested(itemSubject.getId())) {
         dml("delete from " + TABLE_SUBJECT + " where id = '" + itemSubject.getId() + "'");
       }
       String insert = "insert into TABLE_SUBJECT .....";
       dml(insert);
     }
    
     public void cleartable_subject() {
       String delete = "delete from " + TABLE_SUBJECT;
       dml(delete);
     }
    
    public long subject_size() {
       if (db == null) {
         db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READWRITE);
       }
       try {
         long count = DatabaseUtils.queryNumEntries(db, TABLE_SUBJECT);
         return count;
       } catch (Exception e) {
         e.printStackTrace();
         return 0;
      }
     }
    
     private Boolean checkSubject(String id) {
       String select = "select * from " + TABLE_SUBJECT + " where id = '" + id + "'";
       Cursor cursor = getData(select);
       return cursor != null && cursor.getCount() > 0;
     }
    
     public ArrayList<ItemSubject> loadDataSubject() {
        ArrayList<ItemSubject> arrayList = new ArrayList<>();
        String select = "select * from " + TABLE_SUBJECT;
        Cursor cursor = getData(select);
        if (cursor != null && cursor.getCount() > 0) {
         cursor.moveToFirst();
         for (int i = 0; i < cursor.getCount(); i++) {
             String id = cursor.getString(cursor.getColumnIndex(TAG_ID));
             String course = cursor.getString(cursor.getColumnIndex(TAG_COURSE_NAME));
             ....
             ItemSubject objItem = new ItemSubject(id, courseId,...);
             arrayList.add(objItem);
             cursor.moveToNext();
         }
         cursor.close();
        }
        return arrayList;
       }
    
       //There are more similar methods for other tables
    

我正在片段和活动中访问这些方法,例如

     dbHelper = DBHelper.getInstance(getActivity());

     if ((dbHelper.subject_size() >= 1){
      dbHelper.cleartable_subject();
      for (int i = 0; i < arrayListSubject.size(); i++) {
                dbHelper.addToSubject(arrayListSubject.get(i));
            }
            arrayListSubject = dbHelper.loadDataSubject();
     }

很抱歉,代码很长,但我认为一切都是必要的。你能帮帮我吗?

【问题讨论】:

    标签: java android memory-leaks android-sqlite


    【解决方案1】:

    您说您在网上查看了很多问题,但您绝对没有查看thisthis。它确实在搜索 5 分钟后突然出现。

    无论如何,如果我是你,为了解决这个问题,我会在关闭连接时包含一个finally 子句。这意味着您需要将数据库助手声明为静态实例变量,并使用抽象工厂模式来保证单例属性。

    您的警告正在发生,因为您无法确保在任何给定时间只有一个 DatabaseHelper 存在。如果mInstance 对象尚未初始化,则会创建一个。如果已经创建了一个,那么它将被简单地返回。

    代码如下:

    public ArrayList<ItemSubject> loadDataSubject() {
        ArrayList<ItemSubject> arrayList = new ArrayList<>();
        String select = "select * from " + TABLE_SUBJECT;
        Cursor cursor = getData(select);
        
        
        if (cursor != null && cursor.getCount() > 0) {
        try {
            cursor.moveToFirst();
                for (int i = 0; i < cursor.getCount(); i++) {
                    String id = cursor.getString(cursor.getColumnIndex(TAG_ID));
                    String course = cursor.getString(cursor.getColumnIndex(TAG_COURSE_NAME));
             ....
                    ItemSubject objItem = new ItemSubject(id, courseId,...);
                    arrayList.add(objItem);
                    cursor.moveToNext();
               }
           finally {
               if (cursor != null)
               cursor.close();
           }
       }
       return arrayList;
    }    
    

    但既然你说我对你的问题的唯一贡献(已经在其他帖子中得到了回答)是改善你缺乏基本英语,那么我不确定你是否可以接受这个作为一个充分的答案。

    【讨论】:

    • 首先非常感谢您的回答。我已经查看了您提供的那些帖子,但它正在创建一些异常(例如尝试打开已经关闭的数据库或类似类型的东西)。
    • 正如你所说 - '你的警告正在发生,因为你不能确保在任何给定时间只有一个 DatabaseHelper 存在。如果 mInstance 对象尚未初始化,则将创建一个。如果已经创建了一个,那么它将被简单地返回。我已经在使用我的 DatabaseHelper 使用 mInstance 对象,它确保只有一个对象。请仔细查看我的问题的代码部分。最后我想说的是,如果你的回答解决了我的问题,我一定会接受你的回答作为解决方案并投票赞成
    • 查看这篇来自 Google 官方 Android 工程师groups.google.com/g/android-developers/c/NwDRpHUXt0U/m/… 的帖子,您不需要关闭连接,因为当进程清理进程资源时,它会作为内核清理进程资源的一部分而关闭被杀了。
    • 我已经解决了我的问题。早些时候,我曾尝试按照您在 finally 块中所说的关闭光标,但它仍然无法正常工作。问题是返回游标的方法 getData() 。我刚刚删除了getData方法并在每个方法中分别初始化了游标,最后在里面调用了cursor.close,所以现在它已经解决了。
    猜你喜欢
    • 1970-01-01
    • 2017-04-15
    • 2013-11-01
    • 1970-01-01
    • 2010-10-03
    • 2010-09-21
    • 2016-06-25
    • 1970-01-01
    • 2015-02-05
    相关资源
    最近更新 更多