leakcanary
leakcanary copied to clipboard
LeakCanary crashing app on start: java.lang.AbstractMethodError: androidx.lifecycle.ViewModel
Description
Hello in our app we use LeakCanary library. We have recently upgraded gradle, kotlin gradle scripts to KTS, etc. Now when we build APK through Android Studio by "Generate Signed APK" or "Generate APKs" or in terminal by "gradlew assembleSomethingDebug" as Debug type it causing crash on start app. Once I remove the LeakCanary library from debugImplementation in build.gradle.kts. It will stop crashing.
Log:
java.lang.AbstractMethodError: abstract method "androidx.lifecycle.ViewModel androidx.lifecycle.ViewModelProvider$Factory.create(java.lang.Class, androidx.lifecycle.viewmodel.CreationExtras)"
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:168)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:137)
at leakcanary.internal.ViewModelClearedWatcher$Companion.install(ViewModelClearedWatcher.kt:52)
at leakcanary.internal.AndroidXFragmentDestroyWatcher.invoke(AndroidXFragmentDestroyWatcher.kt:66)
at leakcanary.internal.AndroidXFragmentDestroyWatcher.invoke(AndroidXFragmentDestroyWatcher.kt:25)
at leakcanary.FragmentAndViewModelWatcher$lifecycleCallbacks$1.onActivityCreated(FragmentAndViewModelWatcher.kt:59)
at android.app.Application.dispatchActivityCreated(Application.java:353)
at android.app.Activity.dispatchActivityCreated(Activity.java:1334)
at android.app.Activity.onCreate(Activity.java:1607)
at androidx.core.app.ComponentActivity.onCreate(ComponentActivity.java:85)
at androidx.activity.ComponentActivity.onCreate(ComponentActivity.java:343)
at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:246)
at com.ilab.spaceti.ui.base.BaseActivity.onCreate(BaseActivity.kt:99)
Version Information
- LeakCanary version: 2.8.1
- Android OS version: 12
- Gradle version: 7.4
- Android Gradle Plugin: 7.1.1
Same thing is happening for me also. But I could not understand the actual reason, but now i understand the reason and trying to find the solution. Removing the dependency is just a workaround.
Basically lifecycle-2.5.0-alpha01 added a new preferred create() method to ViewModelProvider.Factory that takes an additional CreationExtras parameter. LeakCanary's ViewModelClearedWatcher https://github.com/square/leakcanary/blob/79cdab733e1fc2652384e976778c1807537f71d6/leakcanary-object-watcher-android-androidx/src/main/java/leakcanary/internal/ViewModelClearedWatcher.kt#L47 doesn't implement this yet, and due to some optimization quirk (I think) it doesn't work if you build a debug APK, but at least for me was working if I deployed an debug version from Studio. I believe it'll would work if compiled against the newer lifecycle version since it defaults to the old version.
public fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T =
create(modelClass)
Haven't had any time to test either fix, so I might be way off in left field.
Interesting. Any suggested fix from the LeakCanary side? I worry that updating the dependency version might trigger the same crash for users of older versions of the lib.
Also, can you provide a sample project for repro?
So I first verified that adding that method to ViewModelClearedWatcher does solve this issue for me and I'll be using that as a temporary measure.
I then spent way too much time trying to create a simple repro before realizing the trigger is the minsdk. Anything under API 24 will cause the crash. So it somehow ties into the Java 8, desugaring, and Kotlin interface default methods.
Note: You need to install the final debug version of the app. Launching it from Studio will install the APK from app\build\intermediates\apk\debug\app-debug.apk which doesn't crash, but the version after doing a Make Project from app\build\outputs\apk\debug\app-debug.apk will.
I don't really see an easy and clean way of fixing this on LeakCanary side. Looks to be a bug in the gradle plugin side. Possibly a separate module that can be manually specified? Not an area that I'm too familiar with.
Thanks for the super detailed answer and the repro!
Since lifecycle 2.5.0 is still in alpha, we should probably see if this is a known issue / if the alphas can be fixed.
@dougnazar do you think you could file an issue on the Lifecycle project?
https://issuetracker.google.com/issues/230454566
Seeme like this is caused by a missing dependency on androidx.lifecycle
. See https://issuetracker.google.com/230454566#comment4 for details.
I believe this is on purpose. LeakCanary seems to go out of its way to not pull in dependencies that might not be used/wanted. Which was great until this issue popped up.
I'm currently thinking of changing the compileOnly to implementation but removing the androidx module from android-core. Trade off is that it won't pull in androidx automatically but you'd need to specify an additional module if you use androidx.
Not sure which is preferred, or if the LeakCanary devs have a better option.
So this seems to be working for me:
diff --git a/leakcanary-android-core/build.gradle b/leakcanary-android-core/build.gradle
index b13a607a..b8055888 100644
--- a/leakcanary-android-core/build.gradle
+++ b/leakcanary-android-core/build.gradle
@@ -7,7 +7,6 @@ plugins {
dependencies {
api projects.sharkAndroid
api projects.leakcanaryObjectWatcherAndroidCore
- api projects.leakcanaryObjectWatcherAndroidAndroidx
api projects.leakcanaryObjectWatcherAndroidSupportFragments
implementation libs.kotlin.stdlib
diff --git a/leakcanary-object-watcher-android-androidx/build.gradle b/leakcanary-object-watcher-android-androidx/build.gradle
index b979f1bb..26f45de9 100644
--- a/leakcanary-object-watcher-android-androidx/build.gradle
+++ b/leakcanary-object-watcher-android-androidx/build.gradle
@@ -8,8 +8,8 @@ dependencies {
api projects.leakcanaryObjectWatcherAndroidCore
implementation libs.kotlin.stdlib
- // Optional dependency
- compileOnly libs.androidX.fragment
+ // Required as a runtime dependency so desugaring can add default methods on older APIs
+ implementation libs.androidX.fragment
}
android {
and then adding the following to my projects:
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.10-SNAPSHOT")
debugImplementation("com.squareup.leakcanary:leakcanary-object-watcher-android-androidx:2.10-SNAPSHOT")
This is absolutely not the right fix. LeakCanary should not declare an explicit dependency on lifecycle, the whole point of it being optional is that consumers can leverage whichever version they like or even not have that dependency and everything will work just fine. Lifecycle just broke backward compatibility.
Lifecycle 2.5.0-rc02 will include a fix for this: https://android-review.googlesource.com/c/platform/frameworks/support/+/2108693
Closing as this is fixed on the lifecycle side.
Long story short:
- Because leak-canary is intentionally using
compileOnly
for some dependencies, - Until the day Android's "desugaring" has better support for said
compileOnly
, - We need to manually find leak-canary's dependencies, duplicate them in each of our projects, and that just to replace
compileOnly
withimplementation
.
Example
dependencies {
// ...
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$my_lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$my_lifecycle_version"
}
Where my_lifecycle_version
should be 2.5.1
(or maybe newer).