I have a hybrid app, I need a singleton of the Shared ViewModel class, in my composable function. I use Hilt.
my SahreViewModel class:
class SharedViewModel : ViewModel() { ... }
I use my SharedViewModel everywhere in my app, and can get the singleton it in any fragment as:
private val sharedViewModel: SharedViewModel by activityViewModels()
Same I would like to get in the composable function.
I find two workarounds for this
As you said you can fetch the singleton view model by activityViewModels() then you could simply pass it to the composable function. I imagine one needs the ViewModel inside his top-level composable functions only to make the lower-level reusable, so this solution makes much sense to me.
You can simply create another class containing all the logic that you want to be singleton and annotate with #Singleton and inject it to the ViewModel and by that, although you will have different ViewModel objects, the shared logic will be of the same object across the application.
val sharedViewModel: SharedViewModel = viewModel()
viewModel() returns an existing ViewModel or creates a new one in the given scope. The ViewModel is retained as long as the scope is alive. For example, if the composable is used in an activity, viewModel() returns the same instance until the activity is finished or the process is killed.
The viewModel() function automatically uses the ViewModel that Hilt constructs with the #HiltViewModel annotation.
Due to their lifecycle and scoping, you should access and call ViewModel instances at screen-level composables, that is, close to a root composable called from an activity, fragment, or destination of a Navigation graph. You should never pass down ViewModel instances to other composables, pass only the data they need and functions that perform the required logic as parameters.
Link
Related
I have a fragment that implements Recycler View with switches. RecyclerView sets id for every switch in id+=1 way. The problem is I can get nothing from these IDs as soon as calling throws NullableException. I understand that I have to call it correctly from parent, but I don`t get how to do it correctly.
There is the structure of code:
Fragment with ConstraintLayout(R.id.settingsScreen) -> RecylerView(R.id.recyclerView), that creates LinearLayouts(R.id.settingLayout) with switches(R.id.switch).
class ViewHolder{
val l : LinearLayout = view.findViewById(R.id.settingLayout)
}
if (holder.l.findViewById<SwitchCompat>(1100).isActivated){..}
throws java.lang.NullPointerException: Attempt to invoke virtual method 'boolean androidx.appcompat.widget.SwitchCompat.isActivated()' on a null object reference
It is very fragile to create view IDs yourself like this. They could easily collide with IDs generated by the Android build. So if you create IDs, you should be using ViewCompat.generateViewId() to do it safely.
But findViewById is something you generally want to avoid in the first place. It is slow. That's why View Binding is provided, to cache the views so you don't have to keep searching for them.
I highly recommend storing your Views in a collection instead of assigning them IDs. Then you can efficiently pull them from the collection when you need them. You just need to be sure the collection will be garbage collected when you're done with the views (don't create a collection that will outlive the screen the views are on).
You can get the view by using itemView property
Not sure of you are trying to do when you mean custom id.
You can get all views inflated by viewHolder with itemView.
this property is given to ViewHolder after you pass view as parameter in ViewHolder constructor, than ViewHolder will inflate views according with their id's.
than you can get view inside ViewHolder by:
itemView.findViewById<LinearLayout>(R.id.settingLayout)
itemView.findViewById<SwitchCompat>(R.id.switch)
You can look to see more options in google docs
If these are not what you asked for please let me know
I'm extending and API (clikt) and I want to have a custom implementation of the main function. I cannot override since the method is final so I created my own main2 method and I want to prevent people from calling the original main method. is there a way of doing so in Kotlin?
I have a class that extends a class, and implements an interface by delegation. However, when initializing the delegate object, I want to pass a protected property of the superclass. How can I access it? I've tried writing the property name by itself, and accessing super.property but neither works. Is it possible to do this?
You need to create the delegate object first and do your setup after the constructor of your class is done.
If the property you need to access is private or hidden, you will need some custom method to pass the property to the delegate.
Perhaps you might want to rethink your strategy for initialization, and consider a build pattern. Yet it would help us if you where to provide some sample code and explain more in detail.
In my class I'm referencing a utils object that holds some consts. That utils object inherits from a parent utils object that also has consts. In my class, I want to access the parent's companion consts via a reference to the child utils class. Is this possible?
EDIT
This isn't technically necessary (simply referencing the base class works in my specific case) but I'm still interested from a language perspective if this is possible.
Companion objects and their members can only be accessed via the containing class name, not via instances of the containing class. [...] If you try to redeclare a companion object in a subclass, you'll just shadow the one from the base class.
In other words: It's not possible, as both companion objects are completely unrelated.
So DataBinding can now use LiveData in its binding. As part of this, we also have to set to the Data Binding the life cycle like so:
SampleLayoutBinding binding = DataBindingUtil.inflate(this, R.layout.sample_layout)
binding.setLifeCycleOwner(this)
My question is what is the proper way to set this lifecycle owner inside recyclerview? Or even more appropriately, do we need to set the LifeCyclerOwner when using data binding inside recyclerview?
Yes, you need to set LifeCycleOwner to your data-binding. For this purpose you need to pass Activity/Fragment to your RecyclerView.Adapter as LifeCycleOwner interface and set it when you create binding in RecyclerView.Adapter.onCreateViewHolder().
You also can use your own implementation of LifeCycleOwner