bumptech / glide

An image loading and caching library for Android focused on smooth scrolling
https://bumptech.github.io/glide/
Other
34.67k stars 6.12k forks source link

NoSuchMethodError being thrown in Glide.get() in Application onCreate #578

Closed joshzana closed 9 years ago

joshzana commented 9 years ago

Our app analytics are showing a few hundred of these crashes across a few dozen devices:

java.lang.NoSuchMethodError: android.app.ActivityManager.isLowRamDevice
    at com.bumptech.glide.load.engine.cache.MemorySizeCalculator.isLowMemoryDevice(MemorySizeCalculator.java:105) 
    at com.bumptech.glide.load.engine.cache.MemorySizeCalculator.<init>(MemorySizeCalculator.java:37)
    at com.bumptech.glide.load.engine.cache.MemorySizeCalculator$Builder.build(MemorySizeCalculator.java:221)
    at com.bumptech.glide.GlideBuilder.createGlide(GlideBuilder.java:208)
    at com.bumptech.glide.Glide.get(Glide.java:153)
...
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1017)

The devices crashing range from Android 4.4.0 to 5.1.1, and come from Samsung, HTC, and other OEMs.

My code inspection of MemorySizeCalculator makes me think this should be working fine, and I don't understand why the only crashes are in levels where this method should be present. Maybe bad OEM customizations?

Any ideas?

joshzana commented 9 years ago

For completeness, here is how ActivityManagerCompat from support library works:

public static boolean isLowRamDevice(@NonNull ActivityManager am) {
    if (Build.VERSION.SDK_INT >= 19) {
        return ActivityManagerCompatKitKat.isLowRamDevice(am);
    }
    return false;
}

class ActivityManagerCompatKitKat {
    public static boolean isLowRamDevice(ActivityManager am) {
        return am.isLowRamDevice();
    }
}

vs how Glide does it:

@TargetApi(Build.VERSION_CODES.KITKAT)
private static boolean isLowMemoryDevice(ActivityManager activityManager) {
  final int sdkInt = Build.VERSION.SDK_INT;
  return sdkInt < Build.VERSION_CODES.HONEYCOMB
      || (sdkInt >= Build.VERSION_CODES.KITKAT && activityManager.isLowRamDevice());
}
TWiStErRob commented 9 years ago

Thanks for the report, it makes me scratch my head: reading the code makes nothing pop out. I have two theories about Android JVMs (and maybe desktop ones too):

  1. They throw when they enter a method which references and unexistent method.
    This is definitely true for logging, but not throwing as this would imply a lot of errors from Glide.with on older devices which is not reported.
  2. They throw for unexistent methods per statement, which means shortcutting with || and && doesn't work with compatibility, it has to be a normal if-else.
    This looks more plausible, however weird, maybe there's a reason for those extra *Compat<Version> classes in support other than good code structuring practice.

The problem is that these are both just theories, I don't have any evidence pro or contra. Hopefully @sjudd will have some insight, but it may worth asking a SO question, hopefully some Android JVM expert picks it up (just make sure you tag it correctly with android/jvm/dalvik/art).

sjudd commented 9 years ago

Huh yeah I don't have any insight here, but it's pretty easy to change if @TWiStErRob's second theory is correct. I can try and push up a change and maybe @joshzana you can try the snapshot?

joshzana commented 9 years ago

Sure. I'll give it a shot. I don't have a repro though, so it will have to wait for our next release to get enough coverage and see if the fix takes

TWiStErRob commented 9 years ago

You know that it's weird, and probably trumps both of my theories, that you get the crashes on the systems where this method must exist, and not on old ones.

TWiStErRob commented 9 years ago

What is your min/target SDK?

joshzana commented 9 years ago

15/21. Compile SDK 22.

This is for Dropbox Android, so we have a pretty huge sample size.

bubbleguuum commented 9 years ago

I would check in the crash report that the value of Build.VERSION.SDK_INT is correct. Maybe it is a custom ROM with a bogus value. Still it is improbable. It would help to have the logcat lines just preceding the crash as it could contain additional info to identify the exact cause. Sometimes these errors are the consequence of an earlier Dalvik error at loading classes.

sjudd commented 9 years ago

Out of curiosity did you ever figure out a work around for this?

roseJames commented 8 years ago

I get this bug too, I found this bug occurred because of some custom rom modify the "Api Level", for example "Android 4.3,level 19".