Implementing MVC pattern in Android with Kotlin
MVC, aka Model-View-Controller Pattern is a design pattern which was one of the first approaches to describe and implement software contructs in terms of their responsibilities.
It was first introduced by Trygve Reenskaug in 1970s where he used it in SmallTalk-76. It has only evolved ever since, helping developers in different languages and platform.
But, hey what actually MVC is??
(I am sure you have heard about this pattern before, although didn't use it)
In simple terms, in MVC pattern we classify the responsibilities of an application into 3 simple, independent components:
- Model
- View
- Controller
In layman terms, Model is the data part of the application. It manages the data, logic and rules of the application. View is the UI part.(Pretty simple,eh?). And Controller connects View to the Model and vice versa.
What about Android and MVC ?
I am gonna explain this by following an example: A note taking app.
This app will have a EditText where we enter some text and it gets saved to our Database on a button clicked. (Simple enough!!)
1. View part
We are gonna first create an interface.
interface NoteView {
/**
* Returns the root view, i.e, the inflated layout file
*/
fun getRootView() : View
interface NoteSavedListener{
/**
* Callback function which will be used by our controller to do its things when a note is saved
*/
fun onNoteSaved(note: String)
}
fun setListener(listener: NoteSavedListener)
}
(Why I used an interface here? Find out in the next episode of Dragon Ball Super... Sad reactx only T.T)
Now, lets create an implementation of our interface:
( Here's come the magic )
class NoteViewImp(layoutInflater: LayoutInflater) : NoteView, OnClickListener{
private var mRootView = layoutInflater.inflate(R.layout.note_layout, null)
var noteSavedListener : NoteSavedListener? = null
init{
mRootView.save_btn.setOnClickListener(this)
}
@Override
fun getRootView() = mRootView
@Override
fun setListener(listener: NoteSavedListener){
noteSavedListener = listener
}
@Override
fun onClick(view: View){
val note = mRootView.note_editText.text.toString()
Log.d("debug", "Save Button Clicked")
noteSavedListener?.onNoteSaved(note)
}
}
Now it is upto the controller to use this View implementation, set a NoteSavedListener on and do whatever it wants to do with the note entered using the callback.
2. Controller Part
Here comes the most interesting part of MVC. The bridge between your View and Model. We implement the Activity as our Controller.(Why?)
class AwesomeActivity: AppCompatActivity(), NoteSavedListener{
private lateinit var mNoteView : NoteView
@Override
fun onCreate(savedInstanceState: Bundle?){
super.onCreate(savedInstanceState)
mNoteView = NoteViewImp(layoutInflater)
setContentView(mNoteView.getRootView())
mNoteView.setListener(this)
}
@Override
fun onNoteSaved(note: String){
Log.d("debug", "Saving note: $note")
// Save your note here
// Use content providers, room persistence libraries, whatever you wanna // do with this note, do it. The implementation doesn't matter to your // View and Controller
}
}
As you can see, its a pretty neat code and self explanatory. But this is not where the magic of MVC pattern stops.
The Magic Trick
As you can see you are using only the inteface provided by NoteView interface in your controller and only instantiating it with your implementation, you can implement your View in any way, change styles, add new widgets, show a progress dialog, it doesn't matter, to the Controller and Model. You can create infinitely many Views and the same controller and model will work with all of them.
So where's the Model part?
You probably can guess it now, how to implement your data part.
Conclusion
MVC pattern is one of the many architectural pattern used world-wide on many platforms. Be it android development, or web developement or your desktop software developement.
Personally, it's my favorite.
There's also a MVP(Model-View-Presenter) pattern similar to MVC. I advice you to look it up on Google sometime.
Copyrights
Cover image taken from here