amrz
amrz

Reputation: 111

Lateinit property viewModel has not been initialized

I initialized viewModel with this line viewModel = (activity as NewsActivity).viewModel in BreakingNewsFragment but, recived below error. How i can fix this problem?! thanks for your help

BreakingNewsFragment

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())
    }


}

Error:

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

Upvotes: 7

Views: 15116

Answers (6)

Amit Verma
Amit Verma

Reputation: 1

For solving this error, you have to put this code in your activity as well as in your fragment both

in Newsactivity:-

val newsResporiaty = NewsResporiaty(ArticleDatabase(requireContext()))
val viewModelFactory = NewsViewModelProviderFactory(newsResporiaty)
viewModel = ViewModelProvider(this,viewModelFactory).get(NewsViewModel::class.java)

And also your in fragmets:-

val newsResporiaty = NewsResporiaty(ArticleDatabase(requireContext()))
val viewModelFactory = NewsViewModelProviderFactory(newsResporiaty)
viewModel = ViewModelProvider(this,viewModelFactory).get(NewsViewModel::class.java)

This worked for me.

Upvotes: 0

Sijan Neupane
Sijan Neupane

Reputation: 116

I know it's late but I'm happy to find the solution:

The problem was fragment tag of xml.

I changed the fragment tag to androidx.fragment.app.FragmentContainerView.

and initializing the fragmentcontentview and setting up nav controller:

val navHostFragment= supportFragmentManager.findFragmentById(R.id.newsNavHostFrag) as NavHostFragment
val navController= navHostFragment.navController
bottomNavigationView.setupWithNavController(navController)

Upvotes: 4

Amit Kumar
Amit Kumar

Reputation: 33

If you are using fragment like this:-

<FrameLayout
    android:id="@+id/flFragment"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <fragment
        android:id="@+id/newsNavHostFragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/news_nav_graph" />

</FrameLayout>

then you have to change your appcompat dependency version 1.3.1 to 1.2.0 like this

implementation 'androidx.appcompat:appcompat:1.2.0'

but if you are using latest dependency version i.e 1.3.1 then you have to use

<androidx.fragment.app.FragmentContainerView
        android:id="@+id/newsNavHostFrag"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/news_nav_graph"/>

and in MainActivity.kt change this :-

bottomNavigationView.setupWithNavController(newsNavHostFragment.findNavController())

to this:-

val navHostFragment= supportFragmentManager.findFragmentById(R.id.newsNavHostFrag) as NavHostFragment
    val navController= navHostFragment.navController
    bottomNavigationView.setupWithNavController(navController)

Upvotes: 1

Deep Shah
Deep Shah

Reputation: 11

Use this dependency instead:

implementation 'androidx.appcompat:appcompat:1.2.0' 

and use this version only. I used to use implementation 'androidx.appcompat:appcompat:1.3.1', and that creates the same error as you are facing.

Try once and use implementation 'androidx.appcompat:appcompat:1.2.0' dependency and exact the same version - that's what worked for me.

Upvotes: 1

Medha
Medha

Reputation: 261

Use below line instead of lateinit var viewModel: MainViewModel

private val viewModel:MainViewModel by activityViewModels()

Also , if you can't import it check for this dependency in app level build.gradle

implementation 'androidx.fragment:fragment-ktx:1.1.0'

and remove this line : viewModel = (activity as NewsActivity).viewModel

Upvotes: 0

SVK
SVK

Reputation: 746

  1. Firstly why you are using same View Model for fragment and activity ?
    This approach is incorrect and may lead to inconsistent data and memory leaks.
    Ideally fragment and activity should have their own independent View Model.
    For example:
    a) NewsActivity and NewsViewModel
    b) BreakingNewsFragment and BreakingNewsViewModel

  2. This separates the code by following the Separation of concerns principle and you will get benefit from this as your application logic grows.
    And If you are looking for shared behavior/data, please used Shared View Model.

  3. Secondly, instead of using the View Model from NewsActivity you should initialize it completely in BreakingNewsFragment, the way you did in 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)     

Upvotes: 4

Related Questions