visit
Model is the data layer. Usually, it can be a Repository and it talks to the database and the network.
View is the display level. On Android, this would be Activity, Fragment, or Custom View and should ideally be as dumb as possible.
This is the simplest pattern in Android, where the main business logic is contained in the Model class, and the View and Controller are implemented by the Activity and Fragment.
interface BooksRepository {
fun fetchBooks(): List<Book>
fun saveInFavorites(id: Long): Boolean
fun removeFromFavorites(id: Long): Boolean
}
data class Book(val id: Long, val title: String, val author: String)
class MainFragment : Fragment(R.layout.fragment_main) {
private lateinit var booksRepository: BooksRepository
private lateinit var booksRV: RecyclerView
private val adapter = BooksListAdapter()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
booksRV = view.findViewById(R.id.books_rv)
booksRepository.fetchBooks {
adapter.submitList(it)
}
}
companion object {
@JvmStatic
fun newInstance() = MainFragment()
}
}
Everything seems to be fine, but at first glance, over time, our MainFragment
code will grow and it will be difficult to maintain it.
Presenter - a layer between View and Model. The View passes the events to it, and the Presenter passes them on, if necessary, calls the Model, and returns the data to the View for rendering.
Presenter features:
Cons
MVP example.
Creating the MainView interface:interface MainView {
fun setBooks(books: List<Book>)
fun showLoading()
fun hideLoading()
fun showError(message: String)
}
class MainPresenter(private val view: MainView) {
private lateinit var booksRepository: BooksRepository
init {
booksRepository = BooksRepositoryImpl()
}
fun bind() {
view.showLoading()
}
fun fetchBooks() {
booksRepository.fetchBooks {
view.hideLoading()
view.setBooks(it)
}
}
}
class MainFragment : Fragment(R.layout.fragment_main), MainView {
private lateinit var booksRV: RecyclerView
private lateinit var progressBar: ProgressBar
private val adapter = BooksListAdapter()
private lateinit var presenter: MainPresenter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
booksRV = view.findViewById(R.id.books_rv)
progressBar = view.findViewById(R.id.progress_bar)
presenter = MainPresenter(this)
presenter.bind()
presenter.fetchBooks()
}
override fun setBooks(books: List<Book>) {
adapter.submitList(books)
}
override fun showLoading() {
progressBar.visibility = View.VISIBLE
}
override fun hideLoading() {
progressBar.visibility = View.GONE
}
override fun showError(message: String) {
}
companion object {
@JvmStatic
fun newInstance() = MainFragment()
}
}
What's going on?
onViewCreated()
method, creates a Presenter instance and passes itself to the constructor.