Android 事件:APP_SCOUT_HANG 警告 SQLite

问题描述 投票:0回答:2

在 Adroid 中,我使用 Retrofit2 调用我的服务器来获取数据。

在 onResponse 检查数据库中的版本后,我正在删除并重新创建数据库中的表,然后插入数据。一切正常,数据填写正确,但每次我在控制台中都会收到警告。

这是我的代码的一部分:

  @Override
        public void onResponse(@NonNull Call<List<Movie>> call, @NonNull Response<List<Movie>> response) {
            movieList = response.body();
            myDb = new DatabaseHelper(getApplicationContext());

            if (movieList != null) {
                if (response.isSuccessful() && movieList.size() > 0) {int liveVersion = 0;

                    liveVersion = Integer.parseInt(movieList.get(0).getVersiondb());

                    if (liveVersion>version || version==0) { myDb.clearTable();

                        for (int i = 0; i < movieList.size(); i++) {
                            myDb.insertData(movieList.get(i).getKateg(),movieList.get(i).getFullname(), movieList.get(i).getVersiondb());
                        }
                    }
                } } 
        }

   void clearTable() {
        SQLiteDatabase db = this.getWritableDatabase();
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        db.execSQL("CREATE TABLE " + TABLE_NAME + "(ID INTEGER PRIMARY KEY AUTOINCREMENT, KATEG TEXT, FULLNAME TEXT, VERSION TEXT)");
        db.close();
    }

void insertData(String kateg, String fullname, String version) {
    SQLiteDatabase db = this.getWritableDatabase();

    ContentValues contentValues = new ContentValues();
    contentValues.put(COL_2,kateg);
    contentValues.put(COL_3,fullname);
    contentValues.put(COL_4,version);

    db.insert(TABLE_NAME,null,contentValues);db.close();
}

警告说:

(当前消息:持续时间=5005ms seq=39 h=android.os.Handler c=retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1$$ExternalSyntheticLambda0) MIUIScout 应用 myapp.com W 事件:APP_SCOUT_HANG 线程:主回溯: 在 java.lang.String.charAt(本机方法)
在 java.lang.String.equals(String.java:1271)
在 android.database.DatabaseUtils.getSqlStatementType(DatabaseUtils.java:1574) 在 android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1050) 在 android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:654)
在 android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:590)
在 android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:62)
在 android.database.sqlite.SQLiteStatement。(SQLiteStatement.java:34)
在 android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1700)
在 android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1571)
my.app.DatabaseHelper.insertData(DatabaseHelper.java:99)
在 my.app.StartActivity$1.onResponse(StartActivity.java:84)
在retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$retrofit2-DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
在retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1$$ExternalSyntheticLambda0.run(来源未知:6)
在 android.os.Handler.handleCallback(Handler.java:938)
在 android.os.Handler.dispatchMessage(Handler.java:99)
在 android.os.Looper.loopOnce(Looper.java:210)
在 android.os.Looper.loop(Looper.java:299)
在 android.app.ActivityThread.main(ActivityThread.java:8319)
在 java.lang.reflect.Method.invoke(本机方法)
在 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1038)

在我加粗的一行中,它指向

insertData
方法,但是,由于它毫无问题地插入了所有内容,我不确定出了什么问题。

android android-sqlite
2个回答
0
投票

我认为这可能与

db.close()
有关,因为我在循环中每次插入后都会关闭数据库。

我删除了

db.close()
,现在警告消失了。


0
投票

该警告似乎是由于主线程延迟过多所致。关闭数据库然后重新打开数据库相对来说比较消耗资源。

此外,像每次插入一样,执行许多单个事务本身也是高效的。

您不仅不应该关闭并重新打开数据库,而且您也许应该考虑在单个事务中执行循环中的所有插入。

  • 也许还考虑到可能不需要自动增量,因为仍然会生成 id 列。自动增量增加了另一个增加资源使用的因素。请参阅 https://www.sqlite.org/autoinc.html(第一段警告有关此方面的信息)。

也许考虑以下内容(即松散地基于您的代码)

为了方便不获取数据库实例,两个版本的

insertData
方法:-

void insertData(SQLiteDatabase db, String kateg, String fullname, String version) {
    if (db == null) db = this.getWritableDatabase();
    ContentValues contentValues = new ContentValues();
    contentValues.put(COL_2, kateg);
    contentValues.put(COL_3, fullname);
    contentValues.put(COL_4, version);
    db.insert(TABLE_NAME, null, contentValues);
}

void insertData(String kateg, String fullname, String version) {
    insertData(null, kateg, fullname, version);
}
  • 请注意,后者不需要传递当前/正在使用的 SQliteDatabase,因为它随后会调用 core/first
    insertData
    方法,并将 SQLiteDatabase 设置为 null(因此会获取 SQLiteDatabase)。

不使用

clearTable
方法,因为删除行可能更有效(无论如何删除表都必须这样做)。相反,删除嵌入在建议的
insertAfterClearIfApplicable
方法中(显然可以更改方法名称以适应)

  • 注意以适应答案的简洁性,并且至少通过语法检查电影列表而不是响应。显然您可能希望进行相应修改。答案的真正目的是展示什么可能更有效,即
  1. 删除所有行而不是删除表
  2. 在单个事务中体现所有数据库操作

代码:-

void insertAfterClearIfApplicable(List<Movie> movieList, int liveVersion) {
    if (movieList == null || movieList.size() < 1) return; /* nothing to do so return */
    SQLiteDatabase db = this.getWritableDatabase(); /* get the SQLiteDatabase */
    db.beginTransaction(); /* Start a transaction */
    boolean allDoneOk = true; /*<<<<<<<<<< set to false if the transaction should be rolled back */
    if (movieList.size() > 0) {
        /* Handle the first element i.e. whether or not to delete all rows from the table */
        int version = Integer.parseInt(movieList.get(0).getVersion());
        if (liveVersion > version || version == 0) {
            /* might as well use delete instead of drop as drop has to delete all rows anyway
             *  and saves a little by not having to then create the table again */
            db.delete(TABLE_NAME, null, null);
        }
        /* Insert all of the rows to be added */
        for (Movie m : movieList) {
            insertData(db, m.getKateg(), m.getFullName(), m.getVersion());
        }
        /* unless otherwise flagged set the transaction to NOT rollback */
        /* note if not set as successful then ALL database actions will be rolled back */
        if (allDoneOk) db.setTransactionSuccessful();
     /* end the transaction will commit/write all the actions to the database (if set as susccessful) in a single go
        thus reducing the overheads */
        db.endTransaction();
    }
}
  • 再次请注意以上是近似值,并使用
    List<Movie>
    而不是响应主体,因此应相应地进行调整/更改
    • 即那么答案是为了演示技术而不是实际用途。
© www.soinside.com 2019 - 2024. All rights reserved.