Status Update
Comments
al...@google.com <al...@google.com> #2
Can you provide a bit more details how PRAGMA wal_autocheckpoint
is failing to work in onOpen? When you run the PRAGMA statement again later is the result different than what you expected?
Room does not expose onConfigure but you can pass an open helper factory that creates an open helper that implements onConfigure, see: FrameworkSQLiteOpenHelperFactory
to create the helper to delegate to the other methods you're not interested on. Let me know if this helps.
ch...@google.com <ch...@google.com> #3
Actually, looking at the framework's binding implementation it seems wal_autocheckpoint
is a per connection configuration, you essentially have to execute that PRAGMA before any query, since neither the framework or Room offers a callback for configuring an individual SQLiteConnection. So I'm not sure you'll be able to successfully and nicely disable auto checkpoint.
I'm curious now as to why do you want to disable auto checkpoints? If it's possible to know that is.
cs...@gmail.com <cs...@gmail.com> #4
The reason is that I have a big transaction that needs to be written (> 20K rows after establishing relations), however after the transaction finishes since the WAL Journal exceeded the autocheckpoint threshold, the SQLite tries to write back the Journal to the DB file, which could take roughly 5 seconds, and during that time the Database is locked from reading and writing, which results in an unpleasant UX as the user waits for 5 seconds until he can be able to see the details of the item.
I tried to commit smaller transactions by chunking the rows into smaller rows, but this made the writing to take more than it should, and also didn't solve the DB read/write block issue part entirely, especially with Android defining the autocheckpoint at 100 pages[1] rather than the default SQLite 1000 pages[2].
So my plan was to disable auto checkpointing entirely, and Schedule a Periodic manual checkpoint that should run as a background task through WorkManager and runs when the app is in background. However as you've mentioned the PRAGMA needs to be executed per connection, and not per open, and that's not supported in Room, or the Framework's SQLite code.
There is a new API introduced since API 30 that exactly solves such a case I'm facing, but not sure if it can be backported. [3]
Right now I've managed to solve my problem by using Requery's version of SQLite since it has better defaults than the Framework's[4], and with that it solved the writing performance that I'm facing, at the expense of the APK size unfortunately.
I think you can close this issue since it won't really solve the use case.
[1]
[2]
[3]
al...@google.com <al...@google.com>
al...@google.com <al...@google.com> #5
I see... Indeed execPerConnectionSQL
would be ideal and was actually introduced for this and similar reasons (to let user apply per connection configurations), but it is tied to the native bindings in the framework. I don't think we can backport it to older APIs, but we can update the SupportSQLiteDatabase
ap...@google.com <ap...@google.com> #6
Thanks for your reply! I think adding it to the SupportSQLiteDatabase would emphasize its importance so that third party SQLite providers like Requery might take it into account and provide a backport that would work on pre-API 30 levels. I've already opened an issue there asking them to support it, but that was before our conversation.[1] If you don't mind I'll link your comment there. (I'll wait for your OK though before doing that)
al...@google.com <al...@google.com> #7
Branch: androidx-master-dev
commit 2e7b221b71de60a3a70589cabfe0816c8a2bba2a
Author: Daniel Santiago Rivera <danysantiago@google.com>
Date: Fri Nov 06 11:35:22 2020
Add default method for execPerConnectionSQL() in SupportSQLiteDatabase
SQLiteDatabase#execPerConnectionSQL() was added in API 30 and cannot be backported but a new default method for it can be declared so those who provide the androidx.sqlite interfaces with unbundled SQLite bindings can implement it. For the default framework implementation of the interface the method will throw an UnsupportedOperationException if the API level is lower than 30. To check if the operation is supported users should call isExecPerConnectionSQLSupported(). This allow us to not add @RequireApi(30) which would prevent unbundled implementations to not offer the functionality to lower API levels.
Bug: 172270145
Test: N/A
Relnote: Add default method for execPerConnectionSQL() in SupportSQLiteDatabase
Change-Id: I86326d81aad82c1efccbb2087c439655c9b4100f
M sqlite/sqlite-framework/src/main/java/androidx/sqlite/db/framework/FrameworkSQLiteDatabase.java
M sqlite/sqlite/api/current.txt
M sqlite/sqlite/api/public_plus_experimental_current.txt
M sqlite/sqlite/api/restricted_current.txt
M sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.java
al...@google.com <al...@google.com> #8
al...@google.com <al...@google.com> #9
03-19 09:45:06.958 24627 24627 E AndroidRuntime: Caused by: android.content.res.Resources$NotFoundException: File res/jnq.xml from drawable resource ID #0x7f0804ea
03-19 09:45:06.958 24627 24627 E AndroidRuntime: at android.content.res.Resources.loadDrawable(Resources.java:3453)
03-19 09:45:06.958 24627 24627 E AndroidRuntime: at android.content.res.Resources.getDrawable(Resources.java:1893)
03-19 09:45:06.958 24627 24627 E AndroidRuntime: at android.support.v7.widget.ResourcesWrapper.getDrawable(ResourcesWrapper.java:131)
03-19 09:45:06.958 24627 24627 E AndroidRuntime: at android.support.v7.widget.VectorEnabledTintResources.superGetDrawable(VectorEnabledTintResources.java)
03-19 09:45:06.958 24627 24627 E AndroidRuntime: at android.support.v7.widget.ResourceManagerInternal.onDrawableLoadedFromResources(ResourceManagerInternal.java:356)
This happens when the weak reference to the Context
goes away, which should never happen. The resources are obtained either from a TintContextWrapper
or AppCompatActivity
, both of which retain a reference to the resources object.
The only way this would happen is if the resources were obtained and cached somewhere, then the wrapper was discarded and the cached instance used.
al...@google.com <al...@google.com> #10
Strike that, this stack trace indicates that the context was present and loadDrawableFromDelegates
returned null. There are quite a lot of reasons this could fail, including:
- inflation of this resource ID ever failed
- the resource is not an XML file
- the delegate's
createFromXmlInner
call returned null - no delegate exists for the tag
al...@google.com <al...@google.com> #11
The root cause was re-entrance to Resources.getDrawable()
. Since it's wrapped, the first call runs through the AppCompat override but subsequent inner calls go to the wrapped class. As such, a <vector>
nested inside anything else would fail to load.
ap...@google.com <ap...@google.com> #12
Branch: androidx-main
commit 22ba40be38aeea0e38d206a94d9ae2e2fb637f25
Author: Alan Viverette <alanv@google.com>
Date: Wed Mar 24 19:26:53 2021
Re-apply "Wrap resources with VectorEnabledTintResources" with fixes
Also fixes TintResources, since it will hit the same issue with
re-entrance. Uses ResourcesCompat to avoid UnsafeNewApi in wrapper.
Adds tests for correctness of resource wrapping classes, which
surprisingly did not exist yet.
This reverts commit 7450da45110f2ddb6de946cac4a3d58ab8a4be58.
RelNote: """Added support for nested tinted resources and vector drawables
in AppCompat resource loading backports. Note, however, that this means
apps cannot override getDrawable() on a custom Resources object when
backports are enabled."""
Bug: 176129022
Test: VectorEnabledTintResourcesTest, TintResourcesTest
Reason for revert: Fixed issue with nested drawables
Change-Id: Ia6b034d5143311a111c31d59afbb37dbeeea2131
M appcompat/appcompat-resources/api/restricted_current.txt
M appcompat/appcompat-resources/src/androidTest/AndroidManifest.xml
A appcompat/appcompat-resources/src/androidTest/java/androidx/appcompat/widget/TestResources.java
M appcompat/appcompat-resources/src/androidTest/java/androidx/appcompat/widget/TintResourcesTest.java
A appcompat/appcompat-resources/src/androidTest/java/androidx/appcompat/widget/VectorEnabledTintResourcesTest.java
A appcompat/appcompat-resources/src/androidTest/res/drawable/tint_nested.xml
A appcompat/appcompat-resources/src/androidTest/res/drawable/vector_nested.xml
M appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourceManagerInternal.java
M appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourcesWrapper.java
M appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/TintResources.java
M appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/VectorEnabledTintResources.java
M appcompat/appcompat/src/androidTest/AndroidManifest.xml
D appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/TintResourcesTest.java
al...@google.com <al...@google.com> #13
So hopefully that doesn't break the world again, but now we can support nested tinting + vectors and custom Resources
objects (but not getDrawable()
overrides).
Description
Component used: appcompat-resources (androidx.appcompat) Version used: 1.1.0 Devices/Android versions reproduced on: OS 4.x (Jelly bean, Kitkat)
Issue Description I am trying to fetch strings via my own
Resources
object for non-English locales. In the attached project, my Hindi string is stored inassets
folder. When I run the app on OS 5 and above, the string is correctly displayed (fetched from assets), whereas, when I run the app on OS 4.3 or (OS < 5.0) it displays English string instead of the correct locale. After debugging I found that when I haveAppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
, on low end devices, it wraps Resources object (my object) intoVectorEnabledTintResources
object. In this class onlygetDrawable
is overridden but the rest of the calls are passed over to the parentResources
object instead ofbaseResources
causing the issue.Suggestion Extend
VectorEnabledTintResources
fromResourcesWrapper
or delegate the rest of the calls to the passedResources
objectAttachments
AppCompatDelegate.setCompatVectorFromResourcesEnabled(false);
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);