Reputation: 111
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
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
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
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
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
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
Reputation: 746
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
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
.
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