Skip to content

Instantly share code, notes, and snippets.

@gfreivasc
Last active October 9, 2019 15:33
Show Gist options
  • Save gfreivasc/c52e5fde20f3b4e9380658db66f7b181 to your computer and use it in GitHub Desktop.
Save gfreivasc/c52e5fde20f3b4e9380658db66f7b181 to your computer and use it in GitHub Desktop.
This is an example of how to achieve MVP with injection through dagger (this version without dagger android)
package com.gabrielfv.sandbox6
import android.app.Activity
import android.app.Application
import android.os.Bundle
import android.view.View
import android.widget.Toast
import dagger.*
import javax.inject.Inject
/**
* Main scoped component you will usually find in Android projects
*/
@Component(modules = [AppModule::class])
interface AppComponent {
fun mainSubcomponentFactory() : MainSubcomponent.Factory
}
class MyApplication : Application() {
/**
* Component must be visible so we can launch our subcomponent with it
*/
lateinit var component: AppComponent
override fun onCreate() {
super.onCreate()
component = DaggerAppComponent.create()
}
}
@Subcomponent(modules = [MainModule::class])
interface MainSubcomponent {
/**
* Allows us to manually inject into our activity
*/
fun inject(activity: MainActivity)
@Subcomponent.Factory
interface Factory {
/**
* Binds the activity instance to the DI graph so we can now inject it as a dependency
* when within the lifetime of our subcomponent
*/
fun create(@BindsInstance activity: MainActivity): MainSubcomponent
}
}
/**
* Module declares it's subcomponent so any component (or subcomponent) can initialize it.
*/
@Module(subcomponents = [MainSubcomponent::class])
interface AppModule
/**
* This module holds reference to MainActivity as a dependency so it cannot be included on other
* components.
*/
@Module
interface MainModule {
/**
* Tells Dagger our MainActivity is an instance of Main.View
*/
@Binds
fun bindsMainView(activity: MainActivity): Main.View
/**
* Tells Dagger our MainPresenter is an instance of Main.Presenter
*/
@Binds
fun bindsMainPresenter(presenter: MainPresenter): Main.Presenter
}
interface Main {
interface View {
fun show(count: Int)
}
interface Presenter {
fun inc()
}
}
class MainActivity : Activity(), Main.View {
/**
* This dependency does not block the instantiation of our activity and prevents
* the cyclic dependency from breaking our code
*/
@Inject lateinit var presenter: Main.Presenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(android.R.layout.activity_list_item)
/**
* Here we get the factory of the subcomponent through our app component,
* create the subcomponent and then ask it to inject the dependencies needed,
* while our activity already exists.
*/
(application as MyApplication).component
.mainSubcomponentFactory()
.create(this)
.inject(this)
val view = findViewById<View>(android.R.id.content)
view.setOnClickListener { presenter.inc() }
}
override fun show(count: Int) {
Toast.makeText(this, "Count $count", Toast.LENGTH_LONG).show()
}
}
/**
* The presenter is only instantiated when our activity already exists, so it can take it
* as a dependency.
*/
class MainPresenter @Inject constructor(private val view: Main.View) : Main.Presenter {
private var count = 0
override fun inc() {
view.show(++count)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment