My BaseFragment:
abstract class BaseFragment<ViewModel : BaseViewModel, Binding : ViewBinding> : Fragment() {
protected abstract val viewModel: ViewModel
private var _binding: Binding? = null
protected val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
_binding = Binding.inflate(inflater, container, false) //This line not working
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initialize()
setupListeners()
observe()
}
abstract fun initialize()
abstract fun setupListeners()
abstract fun observe()
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
But this line does not work _binding = Binding.inflate(inflater, container, false)
There is a working code but as for me this is shit coding:
abstract class BaseFragment<ViewModel : BaseViewModel, T : ViewBinding>() : Fragment() {
private var _binding:T? = null
protected abstract val viewModel: ViewModel
protected val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
val superclass: Type = javaClass.genericSuperclass!!
val aClass = (superclass as ParameterizedType).actualTypeArguments[1] as Class<*>
try {
val method: Method = aClass.getDeclaredMethod(
"inflate",
LayoutInflater::class.java,
ViewGroup::class.java,
Boolean::class.javaPrimitiveType
)
_binding = method.invoke(null, layoutInflater, container, false) as T
} catch (e: Exception) {
e.printStackTrace()
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initialize()
setupListeners()
observe()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
abstract fun initialize()
abstract fun setupListeners()
abstract fun observe()
}
How to do it right anybody has a clean solution. I know the DataBinding has DataBindingUtil but i need for ViewBinding. Is there something similar for ViewBinding
I hope for your answers
.
EDIT
Library: https://github.com/kirich1409/ViewBindingPropertyDelegate
BaseFragment:
abstract class BaseFragment<ViewModel : BaseViewModel, Binding : ViewBinding>(
layoutID: Int
) : Fragment(layoutID) {
protected abstract val viewModel: ViewModel
protected abstract val binding: Binding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupViews()
setupListeners()
setupObservers()
}
abstract fun setupViews()
abstract fun setupListeners()
abstract fun setupObservers()
}
class Fragment : BaseFragment<BaseViewModel, FragmentBinding>(
R.layout.fragment
) {
override val viewModel: BaseViewModel by viewModels()
override val binding: FragmentBinding by viewBinding() // this is from library
override fun setupViews() {
}
override fun setupListeners() {
}
override fun setupObservers() {
}
}
But when it comes to ViewBinding with fragments the scenario changes. Because the lifecycle of the Fragment is different and that of activity is different Here also things go the same as discussed in the above article the naming conventions of the fragment layout are changed to pascal case and properties of the fragment layout to camel case.
Using a base fragment helps you avoid code and pattern repetition. You achieve a clean and readable code with the concepts discussed in this article. That is it for this article. Please share your thoughts on this subject.
When requireBinding () is called outside of the Fragment’s view lifecycle, it will throw an IllegalStateException, similar to the behaviour of requireActivity (). This is the class that makes it possible, I added some comments to explain the details.
To implement the UI of each fragment you may refer to the following codes. Firstly the binding variable which is nullable is assigned to null initially, and also when the view of the fragment gets destroyed, again it has to be set null (which in this case _binding ).
BaseFragment.kt
typealias Inflate<T> = (LayoutInflater, ViewGroup?, Boolean) -> T
abstract class BaseFragment<VB: ViewBinding>(
private val inflate: Inflate<VB>
) : Fragment() {
private var _binding: VB? = null
val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = inflate.invoke(inflater, container, false)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
HomeFragment.kt
class HomeFragment() : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::inflate) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.homeText.text = "Hello view binding"
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With