Hey guys! This is my first article on dev.to, and I am super excited about writing again after a long while. Quickly, let's get into the subject at hand.
Building native Android apps require you have a fair knowledge of object-oriented programming. This forms the basis for this article because we will leverage the concepts of Inheritance to set up a base class. In addition to this, you’ll learn about generics, with practical examples.
One may be curious as to why we would want to add another layer of inheritance to our fragment class? This question is usually common with beginner programmers yet to realize the benefits of inheritance.
What is Inheritance in Object-Oriented Programming (OOP)?
Inheritance is a feature in which a class inherits all the features of another class. The class from which the features are inherited is known as the base class, superclass, or parent class, and the class that inherits the features is known as a derived class, subclass, or child class.
E.g. If Class D extends A, it is inheriting the features of A.
What are Generics?
Generics are simply parameterized types. The idea is to allow type (Integer, String, … etc, and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.
Enough theory, let's get started on creating a base fragment class.
STEP 1:
Create a class BaseFragment that extends a Fragment
abstract class BaseFragment<VBinding : ViewBinding, ViewModel : BaseViewModel> : Fragment() {
open var useSharedViewModel: Boolean = false
protected lateinit var viewModel: ViewModel
protected abstract fun getViewModelClass(): Class<ViewModel>
protected lateinit var binding: VBinding
protected abstract fun getViewBinding(): VBinding
private val disposableContainer = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
init()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpViews()
observeData()
}
open fun setUpViews() {}
open fun observeView() {}
open fun observeData() {}
private fun init() {
binding = getViewBinding()
viewModel = if (useSharedViewModel) {
ViewModelProvider(requireActivity()).get(
getViewModelClass()
)
} else {
ViewModelProvider(this).get(getViewModelClass())
}
}
fun Disposable.addToContainer() = disposableContainer.add(this)
override fun onDestroyView() {
disposableContainer.clear()
super.onDestroyView()
}
}
abstract class BaseFragment<VBinding : ViewBinding, ViewModel : BaseViewModel> : Fragment()
Basically what we've done here is create a BaseFragment
which accepts two types, that is a ViewBinding and a ViewModel. With this class, we move common logic and set up to one place, thereby reducing duplicate codes (boilerplates).
The ViewModel class and the ViewBinding object specified as fields in the base class will be provided by the subclass when getViewModelClass()
and getViewBinding()
are invoked, respectively.
open fun setUpViews() {}
and open fun observeData() {}
are methods with a default empty implementation. This makes it optional for its sub-classes to override. The subclasses are not forced to override these methods.
STEP 2:
With the base class set up, we'll use it by creating another fragment class that extends BaseFragment.
@AndroidEntryPoint
class UserListFragment : BaseFragment<FragmentUserListBinding, UserViewModel>() {
override var useSharedViewModel = true
override fun getViewModelClass() = UserViewModel::class.java
override fun getViewBinding() = FragmentUserListBinding.inflate(layoutInflater)
override fun setUpViews() {
// set up recycler view and bind data to UI
}
}
From the code block above, we have been able to achieve a simple and readable fragment class, using the concepts of inheritance and generics.
In summary,
- 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.
Top comments (9)
Halo Enya, Nice article! But when I try your code for my base fragment, why my application crash when I try to go back to previous fragment ?
the error said 'Fragment no longer exists' did you have the same issue ?
hope you will respond my message. Thanks in advance
Hello @sebastianseno thank you. Could You share the link to your project on github. So i check it out. Thats if this sits well with you.
Hey! Nice article! One thing, shouldn't you clear the binding instance on
onDestroyView
?Yeah Mati. I did not take that into consideration because I was only trying to demonstrate the use of base fragment. However, for the sake of best practices, I will update the code accordingly. Thanks.
Hello Enya,
I want to learn this type of architecture , can you please help me from where can I learn this type of architecture or best article link which explains about base classes and its working.
Thank you,
Disha
Great first article Enya! Looking forward to seeing more of what you write :D
Thanks Harsh... Sure you will 😊
Really helpful article. Can you please share your BaseViewModel class too?
Hey @sarimahmed93 I'm glad you learnt a thing form it. Here's the BaseViewmodel from an old project i worked on. Nothing really fancy. Just extending ViewModel.