leakcanary icon indicating copy to clipboard operation
leakcanary copied to clipboard

LeakCanary crashing app on start: java.lang.AbstractMethodError: androidx.lifecycle.ViewModel

Open petrstetka opened this issue 2 years ago • 13 comments

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

petrstetka avatar Feb 24 '22 17:02 petrstetka

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.

vxplore avatar Apr 01 '22 07:04 vxplore

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.

dougnazar avatar Apr 01 '22 14:04 dougnazar

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?

pyricau avatar Apr 03 '22 14:04 pyricau

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.

dougnazar avatar Apr 06 '22 12:04 dougnazar

Thanks for the super detailed answer and the repro!

pyricau avatar Apr 08 '22 16:04 pyricau

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.

pyricau avatar Apr 15 '22 22:04 pyricau

@dougnazar do you think you could file an issue on the Lifecycle project?

pyricau avatar Apr 15 '22 23:04 pyricau

https://issuetracker.google.com/issues/230454566

dougnazar avatar Apr 26 '22 15:04 dougnazar

Seeme like this is caused by a missing dependency on androidx.lifecycle. See https://issuetracker.google.com/230454566#comment4 for details.

sgjesse avatar May 12 '22 10:05 sgjesse

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.

dougnazar avatar May 12 '22 10:05 dougnazar

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")

dougnazar avatar May 12 '22 17:05 dougnazar

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.

pyricau avatar May 18 '22 18:05 pyricau

Lifecycle 2.5.0-rc02 will include a fix for this: https://android-review.googlesource.com/c/platform/frameworks/support/+/2108693

pyricau avatar Jun 10 '22 21:06 pyricau

Closing as this is fixed on the lifecycle side.

pyricau avatar Nov 11 '22 05:11 pyricau

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 with implementation.

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).

top-master avatar Apr 01 '23 21:04 top-master