我的firebase控制台上的android底部导航视图经常出现膨胀异常。我已经仔细检查了我的代码。我做了一些更改,但应用程序仍然因膨胀异常而崩溃。它没有特定的模式,并且出现在每个品牌和型号以及从 4 到 10 的所有版本的 android 上。最初我虽然这是由于我使用的向量。然后我用PNG替换了所有矢量,但错误仍然存在。根据 firebase 控制台的错误原因是找不到资源异常。 由 android.content.res.Resources$NotFoundException 资源 ID #0x7f0800ac 引起 此异常影响 1% 的用户会话。 我正在使用带有 android navcontroller 的底部导航。 我无法在 firebase 报告的任何设备上重现它。我也尝试使用 AS 模拟器,但问题没有被重现。
这是完整的堆栈跟踪。
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)
这是在 xml 文件的第 97 行
<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" />
这是布局文件的其余部分。这是底部菜单 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>
这是 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>
这是底部导航中使用的样式。
<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>
更新 1 这是我的家庭活动课
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)
}
这是我的proguard配置
# 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.**