rawQuery() 始终立即执行,无论实际查询需要多长时间
rawQuery() always executes immediately, no matter how long the actual query takes
几个小时以来,我一直在绞尽脑汁试图理解为什么一个非常简单的 Android 代码会破坏我应用程序中的基本同步。
下面的方法总是立即执行,尽管它有一个 SQLiteDatabase.rawQuery() 调用。 SQL 查询需要多长时间并不重要:
// this method is always executed instantly, despite the rawQuery() call
private Cursor runRawQueryTest() {
Log.i(TAG,"runRawQueryTest() started");
long timer = System.currentTimeMillis();
// SLOW_SQL_QUERY runs at least a couple seconds:
Cursor c = getDb().rawQuery( SLOW_SQL_QUERY, null );
timer = System.currentTimeMillis() - timer;
// timer below always reports a few milliseconds:
Log.i(TAG,"runRawQueryTest() finished in " + timer + "ms.");
return c;
}
这里是 Logcat:
2020-10-06 23:57:07.609 ... I/MainActivity: runRawQueryTest() started
2020-10-06 23:57:07.621 ... I/MainActivity: runRawQueryTest() finished in 12ms. <<<< "incorrect" timer
看起来方法 runRawQueryTest() 以某种方式内联。它本身不会是一个问题(反正谁关心日志?),因为数据库查询实际上发生在调用 runRawQueryTest():
的方法中
public void onClick(View view) {
long timer = System.currentTimeMillis();
Log.i(TAG, "onClick()" );
Cursor c = runRawQueryTest();
// database query actually happens here:
Log.i(TAG, "cursor.getCount() " + c.getCount());
if ( !c.isClosed() ) c.close();
timer = System.currentTimeMillis() - timer;
Log.i(TAG, "onClick() - done in " + timer + "ms. ");
}
Logcat:
2020-10-06 23:57:07.609 ... I/MainActivity: onClick()
2020-10-06 23:57:07.609 ... I/MainActivity: runRawQueryTest() started
2020-10-06 23:57:07.621 ... I/MainActivity: runRawQueryTest() finished in 12ms.
2020-10-06 23:57:14.223 ... I/MainActivity: cursor.getCount() 1 <<<< actual query
2020-10-06 23:57:14.223 ... I/MainActivity: onClick() - done in 6614ms. <<<< correct timer
真正的问题是,在我的应用程序中,这些数据库调用是使用 RxJava 异步进行的。 rawQuery() 被包裹在一个 Observable 中,像这样:
// RxJava wrapper
public Single<Cursor> makeObservable(final String query) {
return Single
.fromCallable( () -> getCursorOrThrow(query) )
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
正如您可能已经猜到的那样,Observable 几乎立即发出一个项目,因此实际的 SQL 查询在 onNext() 调用之后运行。结果,主线程上发生了太多工作,UI 乱七八糟,尤其是进度条。
如何确保 rawQuery() 方法同步执行?
我唯一的猜测是,所有这一切都是由于 R8 优化不理想所致。但是我的项目有非常标准的“开箱即用”设置。我试图解决这个问题,使用 ProGuard“-dontoptimize”键并尝试使用不同的 Gradle 版本。不幸的是,它没有帮助。我 运行 没主意了。我在概念上做错了什么吗?非常感谢任何帮助!
要点:
https://gist.github.com/DmitryOganezov/c52fd8fcfa4f5be3e6ae5016a6ef7b4d
How can I make sure that the rawQuery() method executes synchronously?
在返回前 getCursorOrThrow()
在 Cursor
上调用 getCount()
。
游标是SQLiteCursor
,lazy-executes第一次使用数据时的查询。这是另一个“非常酷的想法,但对我们现在的做事方式来说很糟糕”。在后台线程上调用 getCount()
会强制 SQLiteCursor
实际加载其数据。
几个小时以来,我一直在绞尽脑汁试图理解为什么一个非常简单的 Android 代码会破坏我应用程序中的基本同步。
下面的方法总是立即执行,尽管它有一个 SQLiteDatabase.rawQuery() 调用。 SQL 查询需要多长时间并不重要:
// this method is always executed instantly, despite the rawQuery() call
private Cursor runRawQueryTest() {
Log.i(TAG,"runRawQueryTest() started");
long timer = System.currentTimeMillis();
// SLOW_SQL_QUERY runs at least a couple seconds:
Cursor c = getDb().rawQuery( SLOW_SQL_QUERY, null );
timer = System.currentTimeMillis() - timer;
// timer below always reports a few milliseconds:
Log.i(TAG,"runRawQueryTest() finished in " + timer + "ms.");
return c;
}
这里是 Logcat:
2020-10-06 23:57:07.609 ... I/MainActivity: runRawQueryTest() started
2020-10-06 23:57:07.621 ... I/MainActivity: runRawQueryTest() finished in 12ms. <<<< "incorrect" timer
看起来方法 runRawQueryTest() 以某种方式内联。它本身不会是一个问题(反正谁关心日志?),因为数据库查询实际上发生在调用 runRawQueryTest():
的方法中 public void onClick(View view) {
long timer = System.currentTimeMillis();
Log.i(TAG, "onClick()" );
Cursor c = runRawQueryTest();
// database query actually happens here:
Log.i(TAG, "cursor.getCount() " + c.getCount());
if ( !c.isClosed() ) c.close();
timer = System.currentTimeMillis() - timer;
Log.i(TAG, "onClick() - done in " + timer + "ms. ");
}
Logcat:
2020-10-06 23:57:07.609 ... I/MainActivity: onClick()
2020-10-06 23:57:07.609 ... I/MainActivity: runRawQueryTest() started
2020-10-06 23:57:07.621 ... I/MainActivity: runRawQueryTest() finished in 12ms.
2020-10-06 23:57:14.223 ... I/MainActivity: cursor.getCount() 1 <<<< actual query
2020-10-06 23:57:14.223 ... I/MainActivity: onClick() - done in 6614ms. <<<< correct timer
真正的问题是,在我的应用程序中,这些数据库调用是使用 RxJava 异步进行的。 rawQuery() 被包裹在一个 Observable 中,像这样:
// RxJava wrapper
public Single<Cursor> makeObservable(final String query) {
return Single
.fromCallable( () -> getCursorOrThrow(query) )
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
正如您可能已经猜到的那样,Observable 几乎立即发出一个项目,因此实际的 SQL 查询在 onNext() 调用之后运行。结果,主线程上发生了太多工作,UI 乱七八糟,尤其是进度条。
如何确保 rawQuery() 方法同步执行?
我唯一的猜测是,所有这一切都是由于 R8 优化不理想所致。但是我的项目有非常标准的“开箱即用”设置。我试图解决这个问题,使用 ProGuard“-dontoptimize”键并尝试使用不同的 Gradle 版本。不幸的是,它没有帮助。我 运行 没主意了。我在概念上做错了什么吗?非常感谢任何帮助!
要点: https://gist.github.com/DmitryOganezov/c52fd8fcfa4f5be3e6ae5016a6ef7b4d
How can I make sure that the rawQuery() method executes synchronously?
在返回前 getCursorOrThrow()
在 Cursor
上调用 getCount()
。
游标是SQLiteCursor
,lazy-executes第一次使用数据时的查询。这是另一个“非常酷的想法,但对我们现在的做事方式来说很糟糕”。在后台线程上调用 getCount()
会强制 SQLiteCursor
实际加载其数据。