On a release build with proguard enabled, there is an exception that I didn't really get why it's happening, it's not also reproducable locally. The configurations should be properly done, as I've put them at the bottom of the question after the exception.
Exception is:
Fatal Exception: android.view.InflateException: Binary XML file line #28: Binary XML file line #28: Error inflating class com.example.android.views.CustomImageView
Caused by java.lang.ClassNotFoundException: Didn't find class "com.example.android.views.CustomImageView" on path: DexPathList[[zip file "/data/app/com.example.android-ZRve1QYwB0aaNC0difXwrA==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.android-ZRve1QYwB0aaNC0difXwrA==/lib/arm64, /system/lib64, /vendor/lib64, /product/lib64]]
at dalvik.system.BaseDexClassLoader.findClass + 93(BaseDexClassLoader.java:93)
at java.lang.ClassLoader.loadClass + 379(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass + 312(ClassLoader.java:312)
at android.view.LayoutInflater.createView + 613(LayoutInflater.java:613)
at android.view.LayoutInflater.createViewFromTag + 801(LayoutInflater.java:801)
at android.view.LayoutInflater.createViewFromTag + 741(LayoutInflater.java:741)
at android.view.LayoutInflater.rInflate + 874(LayoutInflater.java:874)
at android.view.LayoutInflater.rInflateChildren + 835(LayoutInflater.java:835)
at android.view.LayoutInflater.rInflate + 877(LayoutInflater.java:877)
at android.view.LayoutInflater.rInflateChildren + 835(LayoutInflater.java:835)
at android.view.LayoutInflater.rInflate + 877(LayoutInflater.java:877)
at android.view.LayoutInflater.rInflateChildren + 835(LayoutInflater.java:835)
at android.view.LayoutInflater.inflate + 515(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate + 423(LayoutInflater.java:423)
at com.example.android.fragments.MyFragment.onCreateView + 160(MyFragment.java:160)
at androidx.fragment.app.Fragment.performCreateView + 2600(Fragment.java:2600)
at androidx.fragment.app.FragmentManagerImpl.moveToState + 881(FragmentManagerImpl.java:881)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState + 1238(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState + 1303(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps + 439(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps + 2079(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether + 1869(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute + 1824(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions + 1727(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run + 150(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback + 808(Handler.java:808)
at android.os.Handler.dispatchMessage + 101(Handler.java:101)
at android.os.Looper.loop + 166(Looper.java:166)
at android.app.ActivityThread.main + 7529(ActivityThread.java:7529)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run + 245(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main + 921(ZygoteInit.java:921)
Related XML file:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.android.views.CustomImageView
android:id="@+id/iconImageView"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:contentDescription="icon"
app:compatElevation="10dp"
tools:ignore="HardcodedText" />
<!-- rest of the layout, not important -->
</RelativeLayout>
The proguard rule is added, and I even added the @Keep
annotation to tell proguard to exclusively not obfuscate the caller package and the class, with everything it has got.
-keep class com.example.android.views.** { *; }
package com.example.android.views;
import androidx.annotation.Keep;
@Keep
public class CustomImageView extends AppCompatImageView
{
// rest of the code
}
If it helps, the view is used in a fragment, and it uses Renderscript to create custom shadows depending on the image source it has. The compatElevation
attribute is defined within attrs.xml
which determines the shadow depth, and does not create some sort of build exceptions. Also works properly, I've tested it multiple times.
The exception does not happen on any version of emulators, or the 4 devices with API 19, 23, 28 and 29 that I have. But it is reported pretty frequently on Crashlytics, so I'm not sure what the issue is here.
The project uses MultiDex
and calls MultiDex.install(this);
on project level application file as well.
I've also analyzed the APK after building it, and I've seen the class exists with the correct leading package for layout inflation. I've also checked the layout.xml file and it also has the correct package and class. Also, in the apk, there are 3 dex files, named classes.dex, classes2.dex, classes3.dex
.
Is there a solution for this? Or should I ignore the exception and move on because it doesn't happen locally, or can say they are device-specific, even though I don't think so?
Any help is appreciated, thank you.