You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin搭建MVVM+Navigation+Firebase Auth应用运行报FragmentContainerView inflate错误

根本原因定位

你看到的Error inflating class androidx.fragment.app.FragmentContainerView是上层抛出的包装异常,实际底层是代码中多处空指针异常,导致Fragment初始化失败,系统加载布局时抛出了包装后的inflate错误。你移除观察代码后不会触发空指针调用,所以能正常运行。具体问题和修复方案如下:


问题1:AppRepo中所有LiveData未初始化直接赋值为null

你的AppRepo里所有LiveData都直接声明为null,后续调用!!访问会直接触发空指针:

// 原错误代码
val userMutableLiveData: MutableLiveData<FirebaseUser>? = null
// 其余LiveData也都是null赋值

修复方案:

将所有LiveData改为直接实例化:

class AppRepo(private val application: Application) {
    val userMutableLiveData = MutableLiveData<FirebaseUser?>()
    val loggedOutMutableLiveData = MutableLiveData<Boolean>()
    val usernameMutableLiveData = MutableLiveData<String>()
    val uriProfilePicMutableLiveData = MutableLiveData<Uri>()

    private val firebaseAuth = FirebaseAuth.getInstance()

    init {
        firebaseAuth.currentUser?.let {
            userMutableLiveData.postValue(it)
        }
    }

    // 其余方法保留,删除所有不必要的!!判空,因为上面的属性都已初始化非空
}

问题2:ViewModel初始化逻辑错误

你在ViewModel里写的open fun ViewModel(application: Application)是普通成员方法,不会在ViewModel实例化时自动执行,导致appRepo和所有LiveData都是null,后续访问直接空指针。

修复方案:

删除该普通方法,改用init块实现初始化逻辑:

open class AuthViewModel(application: Application) : AndroidViewModel(application) {
    private val appRepo = AppRepo(application)
    val userLiveData = appRepo.userMutableLiveData
    val usernameLiveData = appRepo.usernameMutableLiveData
    val uriProfilePicLiveData = appRepo.uriProfilePicMutableLiveData

    @RequiresApi(Build.VERSION_CODES.P)
    fun login(email: String?, password: String?) {
        if (email.isNullOrEmpty() || password.isNullOrEmpty()) return
        appRepo.loginUsers(email, password)
    }
}

注:建议不要将ViewModel直接命名为ViewModel,和SDK自带类重名容易导致导包错误,这里改名为AuthViewModel方便区分


问题3:LoginFragment逻辑错误

  1. 类被声明为abstract抽象类,无法被系统实例化
  2. 观察LiveData的逻辑写在onCreate生命周期中,此时Fragment视图还未创建,调用requireView()获取NavController会直接触发空指针

修复方案:

// 去掉abstract修饰
class LoginFragment : Fragment() {
    private lateinit var emailEditText: EditText
    private lateinit var passwordEditText: EditText
    private lateinit var loginButton: Button
    private lateinit var viewModel: AuthViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel = ViewModelProvider(this)[AuthViewModel::class.java]
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_login, container, false)
    }

    // 视图创建完成后再做视图相关操作
    @RequiresApi(Build.VERSION_CODES.P)
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        emailEditText = view.findViewById(R.id.username)
        passwordEditText = view.findViewById(R.id.password)
        loginButton = view.findViewById(R.id.login)

        loginButton.setOnClickListener {
            val email = emailEditText.text.toString().trim()
            val password = passwordEditText.text.toString().trim()
            viewModel.login(email, password)
        }

        // 观察逻辑移到这里,此时view已经初始化完成
        viewModel.userLiveData.observe(viewLifecycleOwner) { firebaseUser ->
            firebaseUser?.let {
                Navigation.findNavController(view)
                    .navigate(R.id.action_loginFragment3_to_mainUIFragment)
            }
        }
    }
}

注:观察LiveData时优先使用viewLifecycleOwner而不是Activity作为生命周期所有者,避免Fragment销毁后还收到回调导致内存泄露和崩溃


可选优化:MainActivity布局调整

你当前的FragmentContainerView中app:defaultNavHost设为false,无法响应系统返回键的导航回退操作,如果需要该功能可以改成:

app:defaultNavHost="true"

同时删除没有意义的tools:layout_editor_absoluteX和tools:layout_editor_absoluteY属性,tools属性仅在布局预览时生效,运行时无效。


内容的提问来源于stack exchange,提问作者Mohammad Mawed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 22:30:04