问题
I'm trying to implement a BaseFragment in which I will pass the layout resource on it and it should outputs the binding to work in the fragment itself instead of need to do it everytime the fragment is extended.
For example I have this BaseFragment
open class BaseFragment(@LayoutRes contentLayoutId : Int = 0) : Fragment(contentLayoutId) {
private lateinit var onInteractionListener: OnFragmentInteractionListener
val toolbar : Toolbar?
get() {
return if(activity is BaseActivity)
(activity as BaseActivity).toolbar
else
null
}
override fun onAttach(context: Context) {
super.onAttach(context)
setOnInteractionListener(context)
}
...
In which I use like this
class A(): BaseFragment(R.layout.myFragment) { ... }
Now, if I use this I will need to do the definition of the binding class again in my onCreateView
class A(): BaseFragment(R.layout.myFragment) {
private lateinit var binding: MyFragmentBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.myFragment, container, false)
return binding.root
}
override fun onDestroy(){
binding = null
}
}
What I want to implement is that since I'm passwing the layout to my BaseFragment, I want my BaseFragment to handle the creation of the binding and just return me the binding in the fragment which I use to extend BaseFragment
What I want to have is something like this
class A(): BaseFragment(R.layout.myFragment) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.myTextView = ""
}
}
So my question is, how I can implement inside BaseFragment the onDestroy() and the onCreateView to always create a binding for me from the layout I'm passing in ?
I heard that I should use reflection but I'm not that sure on how to accomplish it
回答1:
I didn't hear about the possibility to get the databinding just from a layout, but even if it's possible, I don't think that is the recommended way, because of two reasons:
- Reflection is slow
- It makes things more complicated than they are.
Instead of making magic with Reflection, you could do something like this:
abstract class BaseFragment<out VB: ViewDataBinding>(
private val layout: Int,
// Other Dependencies if wanted
) : Fragment() {
abstract val viewModel: ViewModel
// other variables that all fragments need
// This does not cause any memory leak, because you are not storing the binding property.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = DataBindingUtil.inflate<VB>(inflater, layout, container, false).apply {
lifecycleOwner = viewLifecycleOwner
setVariable(BR.viewModel, viewModel)
}.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// Do some basic work here that all fragments need
// like a progressbar that all fragments share, or a button, toolbar etc.
}
And then, when you still need the bindingProperty, I would suggest the following library (it handles all the onDestoryView stuff etc):
implementation 'com.kirich1409.viewbindingpropertydelegate:viewbindingpropertydelegate:1.2.2'
You can then use this like:
class YourFragment(yourLayout: Int) : BaseFragment<YourBindingClass>() {
private val yourBinding: YourBindingClass by viewBinding()
override val viewModel: YourViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// do binding stuff
}
}
Let me know if this worked for you.
Cheers
来源:https://stackoverflow.com/questions/64650150/how-to-implement-databinding-with-reflection-in-basefragment