android - Lateinit 属性 viewModel 尚未初始化

标签 android kotlin android-fragments mvvm android-viewmodel

我在 BreakingNewsFragment 中使用这一行 viewModel = (activity as NewsActivity).viewModel 初始化了 viewModel,但是收到以下错误。 我该如何解决这个问题?!感谢您的帮助

突发新闻 fragment

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.View
import com.example.simplenewsapp.R
import com.example.simplenewsapp.main.MainViewModel
import com.example.simplenewsapp.NewsActivity
import com.example.simplenewsapp.adapter.NewsRecyclerViewAdapter
import kotlinx.android.synthetic.main.fragment_breaking_news.*


class BreakingNewsFragment : Fragment(R.layout.fragment_breaking_news) {

    lateinit var viewModel: MainViewModel


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewModel = (activity as NewsActivity).viewModel


         ....

NewsActivity

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController
import com.example.simplenewsapp.data.local.ArticleDatabase
import com.example.simplenewsapp.main.MainRepository
import com.example.simplenewsapp.main.MainViewModel
import com.example.simplenewsapp.main.MainViewModelProviderFactory
import kotlinx.android.synthetic.main.activity_news.*

class NewsActivity : AppCompatActivity() {

    lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_news)

        val newsRepository = MainRepository(ArticleDatabase(this))
        val mainViewModelProviderFactory = MainViewModelProviderFactory(newsRepository)
        viewModel =
            ViewModelProvider(this, mainViewModelProviderFactory).get(MainViewModel::class.java)
        
        bottomNavigationView.setupWithNavController(newsNavHostFragment.findNavController())
    }
}

MainViewModelProviderFactory

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class MainViewModelProviderFactory(val mainRepository:MainRepository): ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return MainViewModel(mainRepository) as T
    }
}

MainViewModel

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.simplenewsapp.data.local.models.NewsResponse
import com.example.simplenewsapp.util.Resource
import kotlinx.coroutines.launch
import retrofit2.Response

class MainViewModel(
    val newsRepository: MainRepository
) : ViewModel() {

    val breakingNews: MutableLiveData<Resource<NewsResponse>> = MutableLiveData()
    var breakingNewsPage = 1

    init {
        getBreakingNews("us")
    }

    fun getBreakingNews(countyCode: String) = viewModelScope.launch {
        breakingNews.postValue(Resource.Loading())

        val response = newsRepository.getBreakingNews(countyCode, breakingNewsPage)

        breakingNews.postValue(handleBreakingNewsResponse(response))
    }

    private fun handleBreakingNewsResponse(response: Response<NewsResponse>): Resource<NewsResponse> {
        if (response.isSuccessful) {
            response.body()?.let { resultResponse ->
                return Resource.Success(resultResponse)
            }
        }
        return Resource.Error(response.message())
    }


}

错误:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.simplenewsapp, PID: 4455
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.simplenewsapp/com.example.simplenewsapp.NewsActivity}: android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class fragment
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        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:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class fragment
     Caused by: android.view.InflateException: Binary XML file line #17: Error inflating class fragment
     Caused by: kotlin.UninitializedPropertyAccessException: lateinit property viewModel has not been initialized
        at com.example.simplenewsapp.NewsActivity.getViewModel(NewsActivity.kt:16)
        at com.example.simplenewsapp.ui.fragments.BreakingNewsFragment.onViewCreated(BreakingNewsFragment.kt:29)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2974)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:543)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3112)
        at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3049)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2975)
        at androidx.fragment.app.FragmentStateManager.ensureInflatedView(FragmentStateManager.java:389)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:281)
        at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:141)
        at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
        at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:313)
        at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:292)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
        at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:696)
        at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:170)
        at com.example.simplenewsapp.NewsActivity.onCreate(NewsActivity.kt:20)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        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:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I/Process: Sending signal. PID: 4455 SIG: 9

最佳答案

  1. 首先为什么你对 fragment 和 Activity 使用相同的View Model
    这种做法是不正确的,可能会导致数据不一致和内存泄漏。
    理想情况下, fragment 和 Activity 应该有自己独立的View Model
    例如:
    a) NewsActivity 和 NewsViewModel
    b) BreakingNewsFragment 和 BreakingNewsViewModel

  2. 这将遵循 关注点分离 原则分离代码,随着应用程序逻辑的增长,您将从中受益。
    如果您正在寻找共享行为/数据,请使用 Shared View Model

  3. 其次,不要使用 NewsActivity 中的 View Model 您应该在 BreakingNewsFragment 中完全初始化它,就像在 NewsActivity 中所做的那样。

// Add below code either in your fragment or activity.

 val newsRepository = MainRepository(ArticleDatabase(this))
 val mainViewModelProviderFactory = MainViewModelProviderFactory(newsRepository)
 viewModel = ViewModelProvider(this, mainViewModelProviderFactory).get(MainViewModel::class.java)     

关于android - Lateinit 属性 viewModel 尚未初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66612445/

相关文章:

java - 如何在android中正确处理进度对话框?

kotlin - Kotlin 中 Any 的显式继承 - 可以和如何完成?

android - 滑动tabs的时候,fragment的oncreateView没有被调用,怎么每次都调用oncreateView

android - 菜单按钮只能点击一次

java - Android Studio 中缺少编译器选项 >= 0.8.2

java - 在 java 类中使用 string.xml 资源更改 textView

Java Math 类似于 Kotlin 中的类

java - 如何列出所有根集合并获取所有产品?

android - 保存图片 EXTRA_OUPUT 为空 onActivityResult

android - 有什么办法可以嵌入可滚动的标签吗?