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

Android Kotlin中lateinit viewModel未初始化错误修复求助

问题修复:lateinit property viewModel未初始化错误

报错信息

Caused by: android.view.InflateException: Binary XML file line #19 in com.example.newsappkotlin:layout/activity_main: Binary XML file line #19 in com.example.newsappkotlin:layout/activity_main: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #19 in com.example.newsappkotlin:layout/activity_main: Error inflating class fragment
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property viewModel has not been initialized

相关代码

MainActivity代码

class MainActivity : AppCompatActivity() {
    private lateinit var binding : ActivityMainBinding
    private lateinit var navController: NavController
    lateinit var viewModel : NewsViewModel
    val db : ArticleDatabase? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        val newsRepository =  NewsRepository(ArticleDatabase(this))
        val viewModelProviderFactory = NewsViewModelProviderFactory(newsRepository)
        viewModel = ViewModelProvider(this,viewModelProviderFactory)[NewsViewModel::class.java]
        navController = Navigation.findNavController(this, R.id.newsNavHostFragment)
        setupWithNavController(binding.bottomNavigationView,navController)
    }
}

Fragment代码

class BrakingNewsFragment : Fragment() {
    lateinit var viewModel : NewsViewModel
    lateinit var newsAdapter : NewsAdapter
    private lateinit var binding : FragmentBrakingNewsBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentBrakingNewsBinding.inflate(inflater,container,false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = (activity as MainActivity).viewModel
        setUpRecyclerView()

        viewModel.breakingNews.observe(viewLifecycleOwner, Observer { response ->
            when(response){
                is Resource.Succes -> {
                    response.data?.let {
                        newsAdapter.differ.submitList(it.articles)
                    }
                }
                is Resource.Loading -> {
                    println("abcabc")
                }
            }
        })
    }
    private fun setUpRecyclerView(){
        newsAdapter = NewsAdapter()
        binding.breakingNewsRecyclerView.apply {
            adapter = newsAdapter
            layoutManager = LinearLayoutManager(activity)
        }
    }
}

ViewModelProviderFactory代码

class NewsViewModelProviderFactory(private val newsRepository: NewsRepository) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return NewsViewModel(newsRepository) as T
    }
}

修复方案

核心原因

Activity的onCreate流程中,先调用setContentView加载布局,此时布局内的Fragment会被立即初始化。但你的viewModel是在setContentView之后才完成初始化的,导致Fragment在onViewCreated中访问Activity的viewModel时,该变量还未初始化,最终抛出异常。

具体修复步骤

方案1:调整Activity初始化顺序

将ViewModel的初始化逻辑移到setContentView之前,确保Fragment访问时变量已就绪:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 先初始化ViewModel
    val newsRepository =  NewsRepository(ArticleDatabase(this))
    val viewModelProviderFactory = NewsViewModelProviderFactory(newsRepository)
    viewModel = ViewModelProvider(this,viewModelProviderFactory)[NewsViewModel::class.java]
    
    // 再加载布局及后续操作
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)
    navController = Navigation.findNavController(this, R.id.newsNavHostFragment)
    setupWithNavController(binding.bottomNavigationView,navController)
}

方案2:Fragment通过ViewModelProvider获取共享ViewModel(推荐)

避免直接访问Activity的成员变量,改用Jetpack规范的方式获取与Activity共享的ViewModel,彻底规避初始化顺序问题:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // 替换原有的viewModel赋值逻辑
    viewModel = ViewModelProvider(requireActivity())[NewsViewModel::class.java]
    setUpRecyclerView()

    // 观察逻辑保持不变
    viewModel.breakingNews.observe(viewLifecycleOwner, Observer { response ->
        when(response){
            is Resource.Succes -> {
                response.data?.let {
                    newsAdapter.differ.submitList(it.articles)
                }
            }
            is Resource.Loading -> {
                println("abcabc")
            }
        }
    })
}

方案说明

方案2更符合Jetpack架构设计原则,ViewModel的生命周期与Activity绑定,Fragment通过requireActivity()作为ViewModelStoreOwner获取的实例,会和Activity中的ViewModel保持一致,同时避免了直接依赖Activity成员变量带来的耦合与初始化风险。

内容的提问来源于stack exchange,提问作者Raşit Melih Dinçer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 12:55:26