I am frequently getting inflate exception for android bottom navigation view on my firebase console. I have double checked my code. I made few changes but still application is crashing with inflate exception. It has no specific pattern and occurring on every make and model and also on all versions of android starting from 4 to 10. Initially i though it was due to the vectors i have used. Then I replaced all vectors with PNG but the error still persists. The reason for the error as per firebase console is resource not found exception. Caused by android.content.res.Resources$NotFoundException Resource ID #0x7f0800ac This exception is effecting 1% of user sessions. I am using bottomnavigation with android navcontroller. I am not able to reproduce it on any of the devices which was reported by firebase. I tried with AS emulator as well but the issue is not being reproduced.
Here is complete stack trace.
Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{myapp.com/myapp.com.HomeActivity}: android.view.InflateException: Binary XML file line #97: Binary XML file line #97: Error inflating class com.google.android.material.bottomnavigation.BottomNavigationView
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2956)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3091)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1843)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6758)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:912)
This is on line 97 of xml file
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNav"
style="@style/BottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemTextColor="@drawable/bottom_navigation_text_tint"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
app:menu="@menu/bottommenu" />
Here are rest of the layout file. This is bottom menu xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/fragHome"
android:icon="@drawable/home"
android:title="@string/home" />
<item
android:id="@+id/fragUsage"
android:icon="@drawable/usage"
android:title="@string/usage" />
<item
android:id="@+id/fragWishList"
android:icon="@drawable/withList"
android:title="@string/withList" />
<item
android:id="@+id/fragShop"
android:icon="@drawable/cart"
android:title="@string/shop" />
<item
android:id="@+id/fragMore"
android:icon="@drawable/more"
android:title="@string/more" />
</menu>
This is Bottom_navigation_text_tint
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorPrimary" android:state_checked="true" />
<item android:color="@color/lightGrey" />
</selector>
This is the style used on bottom navigation.
<style name="BottomNavigationView">
<item name="itemTextAppearanceActive">
@style/TextAppearance.BottomNavigationView.Active
</item>
<item name="itemTextAppearanceInactive">
@style/TextAppearance.BottomNavigationView.Inactive
</item>
</style>
<style name="TextAppearance.BottomNavigationView.Inactive">
<item name="android:textSize">@dimen/_8sdp</item>
<item name="fontFamily">@font/roboto_regular</item>
</style>
<!-- active tab icon style -->
<style name="TextAppearance.BottomNavigationView.Active">
<item name="fontFamily">@font/roboto_regular</item>
<item name="android:textSize">@dimen/_8sdp</item>
</style>
Update 1 Here is my home activity class
class HomeActivity : AppCompatActivity(), HasSupportFragmentInjector,
NavigationView.OnNavigationItemSelectedListener,
ConfirmationDialogue.OnActivateClicked, Injectable,
DrawerLocker, DialogAccounts.OnActivateClicked, DialogAccounts.OnDismissClicked {
private var isMaintenance: Boolean = false
@Inject
lateinit var notificationRepo: NotificationRepo
private lateinit var drawerToggle: ActionBarDrawerToggle
@Inject
lateinit var tokenRepository: TokenRepository
@Inject
lateinit var hyperLinksRepository: HyperlinkRepository
@Inject
lateinit var remoteDataSource: RemoteDataSource
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
override fun supportFragmentInjector() = dispatchingAndroidInjector
private lateinit var navController: NavController
private lateinit var bottomNav: BottomNavigationView
private lateinit var mActionBar: View
private lateinit var btnHamBurger: ImageButton
private lateinit var sideNavView: NavigationView
private lateinit var btnBell: ImageButton
private lateinit var drawerLayout: DrawerLayout
private lateinit var userDetails: RegistrationDetails
private lateinit var dialogAccounts: DialogAccounts
companion object {
var selected = RegistrationUtility.getUserDetails()
}
override fun onStart() {
super.onStart()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
initViews()
initEvents()
}
override fun onSupportNavigateUp() = navController.navigateUp()
private fun initViews() {
bottomNav = findViewById(R.id.bottomNav)
mActionBar = findViewById(R.id.myActionBar)
btnHamBurger = findViewById(R.id.btnHamBurger)
navController = findNavController(R.id.navigationHostFragment)
sideNavView = findViewById(R.id.nav_view)
btnBell = findViewById(R.id.btnBell)
drawerLayout = findViewById(R.id.drawer_layout)
Glide.with(BaseClass.appContext).asGif().load(R.drawable.loader_png).diskCacheStrategy(
DiskCacheStrategy.ALL
).into(loader_gif)
}
@SuppressLint("IntentReset")
private fun initEvents() {
onDestinationChanged()
sideNavView.setupWithNavController(navController)
bottomNav.setupWithNavController(navController)
sideNavView.setNavigationItemSelectedListener(this)
btnHamBurger.setOnClickListener {
if (!sideNavView.isShown) {
drawerLayout.openDrawer(GravityCompat.END)
}
}
btnBell.setOnClickListener {
navController.navigate(R.id.frag_Notif)
}
drawerToggle = object : ActionBarDrawerToggle(
this,
drawerLayout,
null,
R.string.empty,
R.string.empty
) {
override fun onDrawerOpened(drawerView: View) {
super.onDrawerOpened(drawerView)
setNavHeader()
}
}
drawerToggle.isDrawerIndicatorEnabled = true
drawerLayout.addDrawerListener(drawerToggle)
drawerToggle.syncState()
tvTitle.setOnClickListener {
}
}
private fun onDestinationChanged() {
navController.addOnDestinationChangedListener { _, destination, _ ->
btnBell.visibility = View.VISIBLE
Lingver.getInstance().setLocale(this, getLocale())
when (destination.id) {
R.id.fragBundles -> tvTitle.text = getString(R.string.bundles)
//other code
}
}
}
private fun setNavHeader() {
userDetails = RegistrationUtility.getUserDetails()
val headerView = sideNavView.getHeaderView(0)
val view = sideNavView.menu.findItem(R.id.nav_log_version).actionView
val tvVersion = view.findViewById<TextView>(R.id.lblVersion)
var currentVersion = getString(R.string.version) + " " + BuildConfig.VERSION_NAME
if (BuildConfig.DEBUG) {
currentVersion = currentVersion + " " + BuildConfig.FLAVOR
}
tvVersion.text = currentVersion
val navUsername = headerView.findViewById(R.id.tvUserName) as TextView
navUsername.text = userDetails.userName
val nvMobile = headerView.findViewById(R.id.tvUserNumber) as TextView
nvMobile.text = userDetails.mobileNumber
val imgProfile = headerView.findViewById(R.id.ivUserImage) as ImageView
imgProfile.setImageResource(userDetails.userAvatar ?: R.drawable.ic_av1)
}
override fun onBackPressed() {
if (sideNavView.isShown) {
drawerLayout.closeDrawer(GravityCompat.END)
}
if (loader_loader.isVisible) {
loader_loader.visibility = View.GONE
} else {
super.onBackPressed()
}
}
override fun onNavigationItemSelected(menuItem: MenuItem): Boolean {
var screenName = ""
when (menuItem.itemId) {
R.id.fragProfile -> {
navController.popBackStack(R.id.fragHome, false)
navController.navigate(R.id.fragProfile)
screenName = LoggingScreens.MyProfile.screenName
}
// other code.
}
drawerLayout.closeDrawer(GravityCompat.END)
return true
}
override fun setDrawerEnabled(enabled: Boolean) {
val lockMode: Int = if (enabled) {
DrawerLayout.LOCK_MODE_UNLOCKED
} else {
DrawerLayout.LOCK_MODE_LOCKED_CLOSED
}
drawerLayout.setDrawerLockMode(lockMode)
drawerToggle.isDrawerIndicatorEnabled = enabled
}
override fun onDestroy() {
super.onDestroy()
Glide.get(applicationContext).clearMemory();
thread(start = true) {
Glide.get(this).clearDiskCache()
}
}
private fun showUpdateDialog(
title: String,
message: String,
cancelable: Boolean,
buttonText: Int
) {
dialogAccounts = DialogAccounts(
this@HomeActivity,
message,
title,
R.drawable.ic_av1_happy,
this@HomeActivity,
this@HomeActivity,
cancelable,
buttonText
)
dialogAccounts.showDialog()
}
override fun onActivateClicked() {
if (!isMaintenance) {
val intent =
Intent(
Intent.ACTION_VIEW,
Uri.parse("market://details?id=" + applicationContext.packageName)
)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
}
override fun onDismissClicked() {
}
}
interface DrawerLocker {
fun setDrawerEnabled(enabled: Boolean)
}
and this is my proguard configuration
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class screenName to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file screenName.
#-renamesourcefileattribute SourceFile
# Application classes that will be serialized/deserialized over moshi
#project related
-keep class app.com.pk.constants
-keep class app.com.pk.service.model.** { *; }
-keep class app.com.pk.service.database.models.** { *; }
-keep class app.com.pk.languageutility.** { *; }
-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic
-keepattributes *Annotation*
-keepattributes EnclosingMethod
-keepattributes InnerClasses
-dontwarn org.xmlpull.v1.**
-dontwarn android-support-v4.**
-dontwarn com.crashlytics.**
-keep class com.google.android.gms.** { *; }
-dontwarn com.google.android.gms.**
-keep public class com.google.** {*;}
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod
# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit
# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*
# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# For OkHttp 3.x
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
# crashlytics
-keep class com.crashlytics.** { *; }
-dontwarn com.crashlytics.**