I’m working on an app with a bottom navigation bar and struggle when trying to access a sharedViewModel’s data across fragments and adapters. My code is already quite full so I’ll be trying to list it up in short here. If needed, I can of course supply the whole code.
Because of different fragments having to access the same data, I created a sharedViewModel class DeactivatedElementsViewModel
(that’s where things start to get complicated). In an exemplary fragment there is the fragment class DeactivatedJumpElementsFragment : Fragment(R.layout.deactivated_jump_elements_fragment)
accompanied by the adapter myAdapter : RecyclerView.Adapter<MyAdapter.ViewHolder>()
which equips a list inside the fragment with buttons and strings.
In the fragment class I begin with lateinit var sharedViewModel: DeactivatedElementsViewModel
and lateinit var elementeAusStand: Map<String,Array<Any>>
before successfully working with the sharedViewModel
in e.g. onViewCreated
(inside the fragment) like so elementsFromStand= sharedViewModel.elementsFromStand
.
Now I struggle with accessing data from the sharedViewModel
inside the adapter
‘s function onBindViewHolder
.
I tried different approaches like the following:
- directly loading
elementsFromStand
insideonBindViewHolder
by implementing thesharedViewModel
there which leads to the error "Can’t access ViewModels from detached fragment" - loading
elementsFromStand
insideonBindViewHolder
via the sharedViewModel declared in the fragment’s class likeval elementsFromStand= DeactivatedJumpElementsFragment().elementsFromStand
which led to the error of the sharedViewModel being called before initialized. I tried to intercept this by
if (DeactivatedJumpElementsFragment()::elementsFromStand.isInitialized){val elementsFromStand = DeactivatedJumpElementsFragment().elementsFromStand}
which simply
won’t ever be true/ run in runtime although the variable
elementsFromStand
is indeed initialized inonViewCreated()
- using nested functions, trying to call the variable elementsFromStand via a function
getSharedViewModelVariable
fromonCreate()
but I fail to successfully retrieve it this way.
That’s where I need help. How do I (easily?) access the view model’s variables from my adapter?
Thanks for reading and for any hint!
2
Answers
Can you try;
Writing a function in your adapter such as updateData() and call it in your fragment or activity and set the data you get from sharedViewModel. in example, i have a favourites list in recycler view and i get the data from my view model, i added this func. in my adapter class;
}
and in my fragment, i get the data from viewModel and set new data in it with;
Hope this is what you need.
The problem you are facing is that you are trying to access the sharedViewModel from the adapter, which is not a lifecycle owner and does not have a reference to the fragment’s view. A possible solution is to pass the sharedViewModel as a parameter to the adapter’s constructor, and then use it in the onBindViewHolder method. For example:
This way, you can access the sharedViewModel’s data from the adapter without creating a new instance of the fragment or using detached views. However, you should also be careful about updating the data in the sharedViewModel, as it might affect other fragments that are using it. You might want to use LiveData or other observable patterns to handle data changes and notify the adapter accordingly.
Explanation:
The reason why you can’t access the sharedViewModel from the adapter directly is that the adapter is not a lifecycle owner, which means it does not have a lifecycle that is tied to the fragment’s view. The sharedViewModel is scoped to the activity’s lifecycle, which means it can be shared by multiple fragments, but it also requires a lifecycle owner to access it. The fragment is a lifecycle owner, and it can access the sharedViewModel by using the activityViewModels() delegate, which provides the same instance of the sharedViewModel to all the fragments in the same activity. However, the adapter is not a lifecycle owner, and it does not have a reference to the fragment’s view, so it can’t use the activityViewModels() delegate or the viewModels() delegate (which provides a fragment-specific instance of the viewModel).
One way to solve this problem is to pass the sharedViewModel as a parameter to the adapter’s constructor, and then store it as a property in the adapter class. This way, the adapter can access the sharedViewModel’s data from the onBindViewHolder method, which is called when the adapter binds the data to the view holder. This approach is simple and straightforward, but it also has some drawbacks. For example, if the data in the sharedViewModel changes, the adapter might not be aware of it, and it might display outdated or inconsistent data. To avoid this, you might want to use LiveData or other observable patterns to observe the data changes in the sharedViewModel and notify the adapter to update the view accordingly. You might also want to consider the impact of updating the data in the sharedViewModel from the adapter, as it might affect other fragments that are using the same sharedViewModel. You might want to use some logic or events to coordinate the data updates and avoid conflicts or errors.