Fixed
Status Update
Comments
yb...@google.com <yb...@google.com>
am...@gmail.com <am...@gmail.com> #2
*Room, not Realm haha
am...@gmail.com <am...@gmail.com> #3
i'm still skeptical about changing the default to crash because I'm worried that some apps won't handle migrating from older versions properly.
But creating a builder option totally makes sense so that more avare developers can turn it on.
Btw, another nice thing about drop by default is the development time. during development, you can easily increment it and pass the check and then just provide the migration from latest release to current release when shipping the app.
But creating a builder option totally makes sense so that more avare developers can turn it on.
Btw, another nice thing about drop by default is the development time. during development, you can easily increment it and pass the check and then just provide the migration from latest release to current release when shipping the app.
am...@gmail.com <am...@gmail.com> #4
If some apps won't handle migrating and it is convenient for them to drop user data, it should not become a problem for those who respect user data. Respecting user data is more important that convenience for *some* lazy devs who can't write JUST ONE LINE to drop tables.
ni...@gmail.com <ni...@gmail.com> #5
Dropping a user data is not always a bad thing, even for offline first apps.
Usually, local modifications are stored in a separate queue that is independent from the data in the db (mostly because data might be overridden).
So even if the data is nuked, local modifications can be restored. It is a fair compromise. In the common case scenario, the device probably had enough time to run any pending jobs before the app is updated so it is rarely a case where app is updated but it had local modifications. Even in that case, data is not lost since the modifications stay in a separate queue.
Worst case scenario of someone failing to write a migration and the app crash looping on the user's device is really bad. It is actually very easy to end up in that situation if the developer simply uninstalls the app to get around the migration because they were focused on solving another problem.
I think the best action for us is to add a "forceMigrations" method into the builder that will always enforce migrations. This way, more aware developers can turn it on (they are also more likely to read the docs).
Usually, local modifications are stored in a separate queue that is independent from the data in the db (mostly because data might be overridden).
So even if the data is nuked, local modifications can be restored. It is a fair compromise. In the common case scenario, the device probably had enough time to run any pending jobs before the app is updated so it is rarely a case where app is updated but it had local modifications. Even in that case, data is not lost since the modifications stay in a separate queue.
Worst case scenario of someone failing to write a migration and the app crash looping on the user's device is really bad. It is actually very easy to end up in that situation if the developer simply uninstalls the app to get around the migration because they were focused on solving another problem.
I think the best action for us is to add a "forceMigrations" method into the builder that will always enforce migrations. This way, more aware developers can turn it on (they are also more likely to read the docs).
am...@gmail.com <am...@gmail.com> #6
There are two offline scenarios IMHO: one is a pure cache mode and you basically do not care about local data, but the other one is where a user generates some content offline. In that scenario it's essential that the data is never deleted. Assuming that all developers respect their user data it is still possible to make a mistake and having user data dropped can be an expensive mistake in that case.
What is the issue with having a default migration that will fix up the schema to have the correct tables + columns? E.g. not dropping tables or columns, just adding them and updating indices etc. That could still fail when the data does not match the constraints set, but at least it prevents data to be lost and sends a signal during development as opposed to silently dropping the whole schema.
What is the issue with having a default migration that will fix up the schema to have the correct tables + columns? E.g. not dropping tables or columns, just adding them and updating indices etc. That could still fail when the data does not match the constraints set, but at least it prevents data to be lost and sends a signal during development as opposed to silently dropping the whole schema.
yb...@google.com <yb...@google.com>
ni...@gmail.com <ni...@gmail.com> #7
Library deciding to *delete* something is a bad idea. At least by default.
How about the scenario when in versionCode=2 I forgot to add the migration, but oh god it rolled out overnight to 1000 users, so at morning I quickly create and upload a versionCode=3 to include the needed migration - only to find that the precious data has been deleted? hardly a good idea.
How about the scenario when in versionCode=2 I forgot to add the migration, but oh god it rolled out overnight to 1000 users, so at morning I quickly create and upload a versionCode=3 to include the needed migration - only to find that the precious data has been deleted? hardly a good idea.
se...@google.com <se...@google.com> #8
First of all, thanks a lot for all the feedback. This is why we label these as alpha and I'm glad it is working.
To be honest, I'm quite torn on this issue.
Let me first address the #6, the offline issue. You don't need to be persisting the user input in the database to make the app work offline. In fact, if you do that, you need to deal with synchronization between the local database and the job that uploads it to ensure that you always upload what is necessary etc.
An easier solution to that problem is to use a work queue for each user modification and de-couple it from the database. This also makes it very easy to architect the rest of the app (e.g. you can freely trim the database when it grows w/o caring about pending data).
That is actually what we did in my previous job and it worked very well. We initially had a queue on top of Square Tape, then wrote Android Priority JobQueue. Mind you it is 5-6 years old but here is something I wrote about it later on:http://www.birbit.com/a-recipe-for-writing-responsive-rest-clients-on-android . By the time, this solution was quite common among the very few offline ready apps.
About auto-migrations, it is something we wanted to do but not very trivial so we postponed to post 1.0. It is also likely to be a tool inside Studio to generate the migration instead of auto-magic migrations.
About #7, same scenario is as worse in the crash case where you'll get thousands of crash loops and uninstalls. It gets just worse if you didn't realize it next morning.
Auto-crashing is also annoying during development, though we can work around it by providing out of the box NukeMigration which will nuke the db and recreate.
Allowing a forceMigrations builder parameter seems like a proper sacrifice to me since it allows the more aware developer to put more strict rules for themselves while allowing the less aware developer to go with their flow. Also makes the common case easier.
Alternatively, we can default to crash but I feel like it will be a decision we'll regret as we receive more bugs that apps which use Room crash after update.
A third option might be to enforce force migration builder parameter, which avoids making a decision. It is an ugly API but will leave the decision to the developer in a more explicit way.
Please keep the comments coming, it is important to get this right for us and we really value your feedback.
To be honest, I'm quite torn on this issue.
Let me first address the #6, the offline issue. You don't need to be persisting the user input in the database to make the app work offline. In fact, if you do that, you need to deal with synchronization between the local database and the job that uploads it to ensure that you always upload what is necessary etc.
An easier solution to that problem is to use a work queue for each user modification and de-couple it from the database. This also makes it very easy to architect the rest of the app (e.g. you can freely trim the database when it grows w/o caring about pending data).
That is actually what we did in my previous job and it worked very well. We initially had a queue on top of Square Tape, then wrote Android Priority JobQueue. Mind you it is 5-6 years old but here is something I wrote about it later on:
About auto-migrations, it is something we wanted to do but not very trivial so we postponed to post 1.0. It is also likely to be a tool inside Studio to generate the migration instead of auto-magic migrations.
About #7, same scenario is as worse in the crash case where you'll get thousands of crash loops and uninstalls. It gets just worse if you didn't realize it next morning.
Auto-crashing is also annoying during development, though we can work around it by providing out of the box NukeMigration which will nuke the db and recreate.
Allowing a forceMigrations builder parameter seems like a proper sacrifice to me since it allows the more aware developer to put more strict rules for themselves while allowing the less aware developer to go with their flow. Also makes the common case easier.
Alternatively, we can default to crash but I feel like it will be a decision we'll regret as we receive more bugs that apps which use Room crash after update.
A third option might be to enforce force migration builder parameter, which avoids making a decision. It is an ugly API but will leave the decision to the developer in a more explicit way.
Please keep the comments coming, it is important to get this right for us and we really value your feedback.
il...@google.com <il...@google.com>
ji...@robinhood.com <ji...@robinhood.com> #9
Re #6 If you want to show the content in the app while it's not synced to the network, it makes sense to store it in the database and additionally keep some sync data. I've built a couple of apps where this was the case: the user adds some content and doesn't really care if it is synced, just that it is synced eventually. By adding it to the database and marking it as "pending" somehow the content can now show up with the rest of the content which in fact simplifies the architecture.
One example is a photo app, where you just want to keep adding your photos to albums and once you are on wifi, everything is synced up to the cloud. Meanwhile you can review and work with your albums without change.
I recently ran into an app doing something similar (adding to the db + sync marker + scheduling a job to sync) so it's not just me doing that :D
It probably boils down to what you are describing, but without the need to consolidate the work queue with the data from the db, because that data in the db is already optimistically updated. Without debating which one is better, I think it's a valid approach.
Nuking the DB for development isn't great either. That same app did not have a way to fetch the previously synced data (for reasons...) and nuking the data during development would therefore not be something that would be very convenient.
Re #7: Of course crashing isn't great either, but if I have the choice of a crashing app for which I can stop roll out and provide an update vs telling users that I trashed their data, I know what I'd pick.
I'd prefer an automatic migration and I think that automatic migration should be at runtime (what if you forget to generate your migration in AS?). For the apps that I wrote, and for users using my library, it seems to match the 90% case for migrations where new entities are added and no data migration is required. If that's not possible then I guess an explicit choice would be best, because ultimately the dev has to indicate someway that it's OK for Room to nuke user data as a convenience or not.
One example is a photo app, where you just want to keep adding your photos to albums and once you are on wifi, everything is synced up to the cloud. Meanwhile you can review and work with your albums without change.
I recently ran into an app doing something similar (adding to the db + sync marker + scheduling a job to sync) so it's not just me doing that :D
It probably boils down to what you are describing, but without the need to consolidate the work queue with the data from the db, because that data in the db is already optimistically updated. Without debating which one is better, I think it's a valid approach.
Nuking the DB for development isn't great either. That same app did not have a way to fetch the previously synced data (for reasons...) and nuking the data during development would therefore not be something that would be very convenient.
Re #7: Of course crashing isn't great either, but if I have the choice of a crashing app for which I can stop roll out and provide an update vs telling users that I trashed their data, I know what I'd pick.
I'd prefer an automatic migration and I think that automatic migration should be at runtime (what if you forget to generate your migration in AS?). For the apps that I wrote, and for users using my library, it seems to match the 90% case for migrations where new entities are added and no data migration is required. If that's not possible then I guess an explicit choice would be best, because ultimately the dev has to indicate someway that it's OK for Room to nuke user data as a convenience or not.
se...@google.com <se...@google.com> #10
To clarify: I wrote "That same app", which is not true, I scrapped a second example to keep my reply shorter, but it was a different app :)
ni...@gmail.com <ni...@gmail.com> #11
Yea, it is always a trade-offs case :). We did the same, just double write into the queue and the database.
As far as I can see, the majority is in favor of crashing in which case we would ahead and change the API to crash by default and add a builder parameter to nuke if migration is missing.
As far as I can see, the majority is in favor of crashing in which case we would ahead and change the API to crash by default and add a builder parameter to nuke if migration is missing.
[Deleted User] <[Deleted User]> #12
In the next version, Room will throw by default.
This behavior can be changed by calling fallbackToDestructiveMigration in the builder.
Thanks for all the feedback.
This behavior can be changed by calling fallbackToDestructiveMigration in the builder.
Thanks for all the feedback.
ub...@gmail.com <ub...@gmail.com> #13
Unfortunately still not fixed up until today, not sure why it has been marked as fixed.
qu...@gmail.com <qu...@gmail.com> #14
still present in alpha 9
yb...@google.com <yb...@google.com>
sa...@google.com <sa...@google.com> #15
With alpha9 I am getting a lot of this when proguarding:
Warning: android.arch.lifecycle.Transformations: can't find referenced class android.arch.core.util.Function
Warning: android.arch.lifecycle.Transformations: can't find referenced class android.arch.core.util.Function
sa...@google.com <sa...@google.com> #16
Addendum to comment #15 :
Happens when using alpha9 + support 26.1.0 but not with alpha9 + support 26.0.0
Happens when using alpha9 + support 26.1.0 but not with alpha9 + support 26.0.0
se...@google.com <se...@google.com> #17
Yep you have to use alpha9-1 + support lib 26.1.0, or alpha9 + support 26.0.0
This class was moved in that release.
This class was moved in that release.
se...@google.com <se...@google.com> #18
To others: could you please share what is broken for you?
ni...@gmail.com <ni...@gmail.com> #19
So with minifyEnabled set to true and with 26.1.0 support library and alpha9-1 android arch, this is the error I still get when I create a release build apk.
java.lang.NoSuchMethodError: No virtual method setRetainInstance(Z)V in class Landroid/arch/lifecycle/HolderFragment; or its super classes (declaration of 'android.arch.lifecycle.HolderFragment' appears in /data/app/package.name/base.apk )
java.lang.NoSuchMethodError: No virtual method setRetainInstance(Z)V in class Landroid/arch/lifecycle/HolderFragment; or its super classes (declaration of 'android.arch.lifecycle.HolderFragment' appears in /data/app/
be...@google.com <be...@google.com> #21
Hello from the tooling side :) Do we have repro steps for this? Can someone attach a full stack trace for this NoSuchMethodError? Is setRetainInstance called reflectively?
ni...@gmail.com <ni...@gmail.com> #22
minifyEnabled set to true and with 26.1.0 support library and alpha9-1 android arch. After building a release apk, installing it, and launching it, it crashes with the following stacktrace.
Stacktrace:
09-29 13:52:13.205 30730 30730 E AndroidRuntime: java.lang.NoSuchMethodError: No virtual method setRetainInstance(Z)V in class Landroid/arch/lifecycle/HolderFragment; or its super classes (declaration of 'android.arch.lifecycle.HolderFragment' appears in /data/app/package_name==/base.apk)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.HolderFragment.<init>(HolderFragment.java:52)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.HolderFragment$HolderFragmentManager.createHolderFragment(HolderFragment.java:148)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.HolderFragment$HolderFragmentManager.holderFragmentFor(HolderFragment.java:186)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.HolderFragment.holderFragmentFor(HolderFragment.java:89)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.ViewModelStores.of(ViewModelStores.java:53)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.ViewModelProviders.of(ViewModelProviders.java:90)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at com.test.fragments.MyFragment.setUpGui(MyFragment.java:170)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at com.test.fragments.MyFragment.onActivityCreated(MyFragment.java:140)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:2363)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1442)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1740)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1809)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:799)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2580)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3221)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3171)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:192)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:560)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:177)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1333)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.Activity.performStart(Activity.java:6992)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2780)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread.-wrap11(Unknown Source:0)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:105)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.os.Looper.loop(Looper.java:164)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6541)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Stacktrace:
09-29 13:52:13.205 30730 30730 E AndroidRuntime: java.lang.NoSuchMethodError: No virtual method setRetainInstance(Z)V in class Landroid/arch/lifecycle/HolderFragment; or its super classes (declaration of 'android.arch.lifecycle.HolderFragment' appears in /data/app/package_name==/base.apk)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.HolderFragment.<init>(HolderFragment.java:52)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.HolderFragment$HolderFragmentManager.createHolderFragment(HolderFragment.java:148)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.HolderFragment$HolderFragmentManager.holderFragmentFor(HolderFragment.java:186)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.HolderFragment.holderFragmentFor(HolderFragment.java:89)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.ViewModelStores.of(ViewModelStores.java:53)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.arch.lifecycle.ViewModelProviders.of(ViewModelProviders.java:90)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at com.test.fragments.MyFragment.setUpGui(MyFragment.java:170)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at com.test.fragments.MyFragment.onActivityCreated(MyFragment.java:140)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:2363)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1442)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1740)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1809)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:799)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2580)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3221)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3171)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:192)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:560)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:177)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1333)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.Activity.performStart(Activity.java:6992)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2780)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread.-wrap11(Unknown Source:0)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:105)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.os.Looper.loop(Looper.java:164)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6541)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
09-29 13:52:13.205 30730 30730 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
be...@google.com <be...@google.com> #23
Are you able to reproduce the issue on an example project that you could share with us?
Looking at the stack trace and corresponding source code, there are direct (statically known) calls all the way from ViewModelProviders.of(...) to HolderFragment.setRetainInstance(...) and I was unable to reproduce the problem.
When you open your APK in Studio with "Build -> Analyze APK", how many dex files are there in the APK? Can you see the setRetainInstance method in android.arch.lifecycle.HolderFragment?
Looking at the stack trace and corresponding source code, there are direct (statically known) calls all the way from ViewModelProviders.of(...) to HolderFragment.setRetainInstance(...) and I was unable to reproduce the problem.
When you open your APK in Studio with "Build -> Analyze APK", how many dex files are there in the APK? Can you see the setRetainInstance method in android.arch.lifecycle.HolderFragment?
ni...@gmail.com <ni...@gmail.com> #24
I see one dex file. And yes I can see setRetainInstance method in android.arch.lifecycle.HolderFragment
ni...@gmail.com <ni...@gmail.com> #25
I will try to get an example project with the same bug for you tonight.
ni...@gmail.com <ni...@gmail.com> #26
These are all the dependencies I've added from the arch lib
compile "android.arch.lifecycle:runtime:1.0.0-alpha9-1"
compile "android.arch.lifecycle:extensions:1.0.0-alpha9-1"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha9-1"
compile "android.arch.persistence.room:runtime:1.0.0-alpha9-1"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha9-1"
compile "android.arch.lifecycle:runtime:1.0.0-alpha9-1"
compile "android.arch.lifecycle:extensions:1.0.0-alpha9-1"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha9-1"
compile "android.arch.persistence.room:runtime:1.0.0-alpha9-1"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha9-1"
dr...@gmail.com <dr...@gmail.com> #27
I met the same problem and I am looking forward to being able to fix it.
qi...@gmail.com <qi...@gmail.com> #28
I have attached a sample project with the bug. The app crashes on start up with the same error.
`java.lang.NoSuchMethodError: No virtual method setRetainInstance(Z)V in class Landroid/arch/lifecycle/HolderFragment; or its super classes (declaration of 'android.arch.lifecycle.HolderFragment' appears in /data/app/com.sample.sample-hQELEWb8KGV9KcOgMhgy3Q==/base.apk)`
It has minify set to true, and the release apk is signed with a keystore with both V1 and V2 checked.
I believe it to be line `viewModel = ViewModelProviders.of(this, viewModelFactory).get(ViewModel.class);` in dashboardfragment.java to be crashing the app.
`java.lang.NoSuchMethodError: No virtual method setRetainInstance(Z)V in class Landroid/arch/lifecycle/HolderFragment; or its super classes (declaration of 'android.arch.lifecycle.HolderFragment' appears in /data/app/com.sample.sample-hQELEWb8KGV9KcOgMhgy3Q==/base.apk)`
It has minify set to true, and the release apk is signed with a keystore with both V1 and V2 checked.
I believe it to be line `viewModel = ViewModelProviders.of(this, viewModelFactory).get(ViewModel.class);` in dashboardfragment.java to be crashing the app.
ni...@gmail.com <ni...@gmail.com> #29
Can you verify on your end if this is an existing bug or if there is a way we can add a rule in proguard to prevent this from occurring?
be...@google.com <be...@google.com> #30
This indeed looks like a bug in our custom shrinker. For now please add "useProguard true" to build.gradle to force ProGuard to be used to shrinking (as opposed to our implementation).
be...@google.com <be...@google.com> #31
OK, to give a bit more context. In 2.x we added our custom implementation of a code shrinker which was disabled by default and considered experimental. It could be enabled by setting `useProguard false` on top of `minifyEnabled true`. We know the DSL is not intuitive, it will be changed in Studio 3.1.
The `useProguard` flag was not documented (seehttps://google.github.io/android-gradle-dsl/2.3/com.android.build.gradle.internal.dsl.BuildType.html ) as this was all considered work in progress. So in this case the fix is just to remove the `useProguard false` line altogether. Obfuscation should be enabled/disabled in the proguard config file as desired.
In 3.0 the bug is fixed and our custom shrinker produces a working APK. It's also the case that in 3.0 the custom shrinker is by default used when building from the IDE for instant run. As before, setting `useProguard true` on top of `minifyEnabled true` will force the ProGuard tool to be used during build, always.
The `useProguard` flag was not documented (see
In 3.0 the bug is fixed and our custom shrinker produces a working APK. It's also the case that in 3.0 the custom shrinker is by default used when building from the IDE for instant run. As before, setting `useProguard true` on top of `minifyEnabled true` will force the ProGuard tool to be used during build, always.
ni...@gmail.com <ni...@gmail.com> #32
So for now, remove useProguard false and when 3.0 is released, we can add that rule back in?
be...@google.com <be...@google.com> #33
Most people should have no need to set the `useProguard` flag explicitly. It's `minifyEnabled` that matters, in combination with the proguard-rules.pro configuration file. I suggest you just remove it.
hq...@gmail.com <hq...@gmail.com> #34
I am getting the following error when I use ROOM library
java.lang.RuntimeException:cannot find implementation for fm.qingting.qtradio.log.j.c. j_c_Impl does not exist.
So now what do I add to proguard rules file or what else should I do?
I get this both with 2.3.3 and 3.0.0 android build plugin.
java.lang.RuntimeException:cannot find implementation for fm.qingting.qtradio.log.j.c. j_c_Impl does not exist.
So now what do I add to proguard rules file or what else should I do?
I get this both with 2.3.3 and 3.0.0 android build plugin.
yb...@google.com <yb...@google.com> #35
Room already ships w/ the following proguard rules:
-keep public class * extends android.arch.persistence.room.RoomDatabase
-dontwarn android.arch.persistence.room.paging.**
So, I'm assuming j_c is your RoomDatabase class,which should've never been obfuscated.
-keep public class * extends android.arch.persistence.room.RoomDatabase
-dontwarn android.arch.persistence.room.paging.**
So, I'm assuming j_c is your RoomDatabase class,which should've never been obfuscated.
bo...@gmail.com <bo...@gmail.com> #36
I don't believe this to be a ProGuard issue. At least not with the final v1.0 release of Arch Components.
If I build the release APK with minifyEnabled true and shrinkResources true, then observers don't work throughout the app.
If however I add useProguard false, even without *any* ProGuard rules, it works.
If I build the release APK with minifyEnabled true and shrinkResources true, then observers don't work throughout the app.
If however I add useProguard false, even without *any* ProGuard rules, it works.
ni...@gmail.com <ni...@gmail.com> #37
We are using the 1.1.1 version for Arch Components. Once we build the release build with minifyEnabled true shrinkResources true, observers don't work throughout the app.
I assume the proguard rules for Arch Components are already included with the library.
We are not able to figure out whats the exact issue. Any help here?
I assume the proguard rules for Arch Components are already included with the library.
We are not able to figure out whats the exact issue. Any help here?
ea...@gmail.com <ea...@gmail.com> #38
Running room integration tests with minifyEnabled true and useProguard false, all test fail due to no such method errors GithubBrowserSample even fails to compile due to proguard warinings
be...@google.com <be...@google.com> #39
At this point you should probably remove the `useProguard` line from build.gradle, the old experimental shrinker was replaced by R8 which doesn't need the flag (see https://developer.android.com/studio/preview/features/#R8-enabled for details). If you still see the issue, please file a separate bug.
Description
Version used: 1.0.0-alpha1
Generated class that implements GenericLifecycleObserver gets cleared by proguard.
Maybe it would be a good idea to provide proguard rules for that inside aar file?
Here is what I came up with in my app:
proguard-rules.pro:
...
## Android architecture components: Lifecycle
-keepclasseswithmembers class * implements android.arch.lifecycle.GenericLifecycleObserver {
<init>(...);
}