Menggunakan Koin sebagai DI pada Android MVP Pattern
Pada kesempatan kali ini saya akan menjelaskan secara singkat bagaimana cara saya menggunakan library library DI (Dependency Injection) yang populer untuk melakukan injection pada Android MVP Pattern.
Struktur MVP Pattern
Karena menurut saya injection menggunakan library library populer seperti Koin, Hilt dan Dagger 2 pada MVP Pattern termasuk sulit.
Sebelum nya mari kita lihat dulu bagaimana struktrur MVP Pattern di Android
class MainActivity : AppCompatActivity(),MainView {
private val presenter: MainPresenter by inject {
parametersOf(this)
}
// rest of the code
}
class MainPresenter(private val mView: MainView) {
fun logMe(name:String) {
mView.logMessage("hello: $name , how are you ?")
}
}
interface MainView {
fun logMessage(name:String)
}
Nah alurnya adalah MainPresenter
Dependent (membutuhkan/bergantung) MainView
dan MainActivity
perlu implement MainView
agar bisa menggunakan MainPresenter
.
Dependency Injection
Apa itu Dependency Injection ? Dependency Injection menurut saya adalah suatu teknik / cara bagaimana membuat suatu class yang membutuhkan class lain agar dapat berjalan.
Mari kita lihat dua contoh penerapan tanpa DI dan menggunakan DI dari Android Official Documentation :
Tanpa DI
class Car {
private val engine = Engine()
fun start() {
engine.start()
}
}
fun main(args: Array) {
val car = Car()
car.start()
}
Tanpa menggunakan DI class Car
akan membuat class Engine
nya sendiri, kekurangan nya adalah class Car
menjadi tightly coupled dan tidak fleksibel bila ingin memilih class Engine
lainnya. Begitu juga bila terjadi masalah pada class Car
kita tidak tau mana yang bermasalah apakah class Car
itu sendiri atau kah class Engine
?
Menggunakan DI
class Car(private val engine: Engine) {
fun start() {
engine.start()
}
}
fun main(args: Array) {
val engine = Engine()
val car = Car(engine)
car.start()
}
Nah bila menggunakan DI class Car
tidak membuat sendiri class Engine
nya melainkan hanya menerima melalui constructor sehingga memberikan fleksibilitas bila ingin memilih class Engine
lainnya. Begitu juga bila terjadi masalah kita bisa mengetahui mana yang bermasalah apakah class Car
atau kah class Engine
itu sendiri
Dependency Injection dengan Koin
Apa itu Koin ? Koin merupakan salah satu library populer yang di gunakan dalam mempermudah Android Developer dalam membuat sebuah class menggunakan teknik DI
Bagaimana cara menggunakan nya ?
Cukup mudah kita perlu membuat module & mendefinisikan component nya, yuk kita lihat satu persatu caranya
- Membuat Module
val myModule = module {
// your dependencies here
}
2. Definisikan Component
Component dari Koin ada 3 yaitu single
, factory
& scoped
berikut penjelasannya :
- single : kita akan membuat sebuah singleton class
- factory : kita akan membuat sebuah class baru setiap kali digunakan
- scoped : kita akan membuat sebuah class yang lifetime nya mengikuti sebuah scope
contoh implementasinya akan seperti ini :
// Car <- Engine
class Engine()
class Car(val engine : Engine)
val myModule = module {
// declare Engine as single instance
single { Engine() }
// declare Car as single instance
// resolving Engine instance with get()
single { Car(get()) }
}
// using Car
val car:Car by inject()
Cukup mudah di mengerti ya, jadi ketika kita ingin menggunakan sebuah class Car
yang membutuhkan class Engine
tanpa perlu membuat nya secara manual kita tinggal membuat mereka menggunakan Koin.
Koin pada MVP Pattern
Nah setelah kita mengetahui struktur dari MVP Pattern , Konsep DI & menggunakan Koin. ada 2 cara bagaimana melakukan DI pada MVP Pattern menggunakan Koin yaitu :
- Binding an Interface
- Passing Parameters — Injected Parameters
Binding an interface
Kita akan mencontoh pada bagian Definition: binding an interface di dokumentasi Koin
// Service interface
interface Service{
fun doSomething()
}
// Service Implementation
class ServiceImp() : Service {
fun doSomething() { ... }
}
Kemudian kita lihat bagaimana cara membuat module & mendefiniskan nya
val myModule = module {
// Will match type Service only
single<Service> { ServiceImp() }
}
Nah kenapa kita melihat contoh binding an interface ? karena pada contoh MVP Pattern MainPresenter
membutuhkan view interface dari MainView
. Yuk kita bikin module nya
val myModule = module {
// declare MainView as single instance
single<MainView> { MainActivity() }
// declare MainPresenter as single instance
// resolving MainView instance with get()
single { MainPresenter(get()) }
}
Setelah itu yuk kita implementasikan pada MainActivity
nya
class MainActivity : AppCompatActivity(),MainView {
private val TAG = this.javaClass.canonicalName
private val presenter: MainPresenter by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
presenter.logMe("Android")
}
override fun logMessage(name: String) {
Log.e(TAG, name )
}
}
Yeay berhasilll !
Passing Parameters — Injected Parameters
Nah cara ini agak sedikit berbeda, kalau cara diatas kita mencoba membuat MainView
dengan MainActivity
sebagai implementasinya, dengan cara ini kita hanya memberikan nya saja, berikut contoh dari dokumentasi nya :
class Presenter(val view : View)
val myModule = module {
single { (view : View) -> Presenter(view) }
}
Okay setelah melihat contoh diatas yuk kita bikin module berdasarkan MVP Pattern kita :
val myModule = module {
factory { (view: MainView) ->
MainPresenter(view)
}
}
Setelah itu yuk kita implementasikan pada MainActivity
nya
class MainActivity : AppCompatActivity(),MainView {
private val TAG = this.javaClass.canonicalName
private val presenter: MainPresenter by inject {
parametersOf(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
presenter.logMe("PassingParameters")
}
override fun logMessage(name: String) {
Log.e(TAG, name )
}
}
Yeaay berhasil jugaaa
Jadi dengan menerapkan 2 cara di atas dapat kita petik kesimpulan bahwa
- Binding an Interface : Mencoba membuat
MainView
dari Implementasi Class nya - Passing Parameters — Injected Parameters : Memberikan (Passing)
MainView
nya saja
Cukup mudah bukan ? Semoga membantu yaa, kalau mau melihat code nya bisa lihat di repo saya dibawah 😄
Terimakasih !
Sampai jumpa lagi
Sumber :
- https://developer.android.com/training/dependency-injection
- https://insert-koin.io/
- https://insert-koin.io/docs/reference/koin-core/definitions
- https://insert-koin.io/docs/reference/koin-core/definitions#definition-binding-an-interface
- https://insert-koin.io/docs/reference/koin-core/injection-parameters/
- https://medium.com/cr8resume/make-you-hand-dirty-with-mvp-model-view-presenter-eab5b5c16e42