$30 off During Our Annual Pro Sale. View Details »

Helping Dagger Help You (Droidcon UK 2018)

Helping Dagger Help You (Droidcon UK 2018)

As applications grow in size, Dagger can help mitigate the pain of dependency management and eliminate the boilerplate of manual dependency injection. Despite this, there are still pain points such as slower compilation times and how to inject objects like activities and views. This talk will cover functionality provided by libraries which build on top of Dagger to reduce these pain points. We'll learn what assisted injection is, why you might use it, and look at a library which simplifies the pattern. And finally we'll attempt to solve the build speed problem so that development builds are as fast as possible without sacrificing Dagger's compile-time safety.

Video: http://uk.droidcon.com/skillscasts/11617-helping-dagger-help-you

Jake Wharton
PRO

October 26, 2018
Tweet

More Decks by Jake Wharton

Other Decks in Programming

Transcript

  1. Helping
    Dagger
    Help
    You
    @JakeWharton

    View Slide

  2. boilerplate
    /ˈbɔɪləpleɪt/
    noun
    standardized pieces of text for use as clauses in
    contracts or as part of a computer program

    View Slide

  3. verbosity
    /vəˈbɒsɪti/
    noun
    the fact or quality of using more words
    than needed; wordiness

    View Slide

  4. View Slide

  5. View Slide

  6. Dagger

    View Slide

  7. Dagger

    View Slide

  8. Service Locator

    View Slide

  9. Manual Dependency Injection

    View Slide

  10. Manual Dependency Injection

    View Slide

  11. Manual Dependency Injection

    View Slide

  12. Service Locator

    View Slide

  13. Dagger

    View Slide

  14. Dagger

    View Slide

  15. Dagger

    View Slide

  16. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    // …
    }Y

    View Slide

  17. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    // which profile do we load?
    }Y

    View Slide

  18. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    // which profile do we load?
    // what initials do we render the avatar placeholder with?
    }Y

    View Slide

  19. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    // which profile do we load?
    // what initials do we render the avatar placeholder with?
    // which image url do we download?
    }Y

    View Slide

  20. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    lateinit var userId: String
    // which profile do we load?
    // what initials do we render the avatar placeholder with?
    // which image url do we download?
    }Y

    View Slide

  21. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    lateinit var userId: String
    // which profile do we load?
    // what initials do we render the avatar placeholder with?
    // which image url do we download?
    }Y
    var userId: String = …

    View Slide

  22. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    lateinit var userId: String
    // which profile do we load?
    // what initials do we render the avatar placeholder with?
    // which image url do we download?
    }Y
    var userId: String = …
    presenter.userId = userId

    View Slide

  23. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    lateinit var userId: String
    // which profile do we load?
    // what initials do we render the avatar placeholder with?
    // which image url do we download?
    }Y
    var userId: String = …
    presenter.userId = userId
    // Use presenter…

    View Slide

  24. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    lateinit var userId: String
    // …
    }Y
    var userId: String = …
    presenter.userId = userId
    // Use presenter…

    View Slide

  25. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y
    var userId: String = …
    presenter.userId = userId
    // Use presenter…

    View Slide

  26. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y
    // Use presenter…

    View Slide

  27. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y
    // Use presenter…

    View Slide

  28. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    @UserId var userId: String
    ) {
    // …
    }Y
    // Use presenter…

    View Slide

  29. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y
    // Use presenter…

    View Slide

  30. class ProfilePresenter @Inject constructor(A
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y

    View Slide

  31. class ProfilePresenter(A
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y

    View Slide

  32. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory
    }Y

    View Slide

  33. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    )G
    }Y

    View Slide

  34. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    )G{
    fun create(userId: String)
    }Z
    }Y

    View Slide

  35. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    )G{
    fun create(userId: String) =
    ProfilePresenter(imageLoader, profilePersistence,
    avatarRenderer, userId)
    }Z
    }Y

    View Slide

  36. class ProfilePresenter(…) {
    // …
    class Factory @Inject constructor(…)G{
    fun create(userId: String) =
    ProfilePresenter(imageLoader, profilePersistence,
    avatarRenderer, userId)
    }Z
    }Y

    View Slide

  37. class ProfilePresenter(…) {
    // …
    class Factory @Inject constructor(…) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader, profilePersistence,
    avatarRenderer, userId)
    }Z
    }Y
    var userId: String = …

    View Slide

  38. class ProfilePresenter(…) {
    // …
    class Factory @Inject constructor(…) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader, profilePersistence,
    avatarRenderer, userId)
    }Z
    }Y
    var userId: String = …
    val presenter = presenterFactory.create(userId)
    // Use presenter…

    View Slide

  39. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer
    ) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader, profilePersistence,
    avatarRenderer, userId)
    }Z
    }Y

    View Slide

  40. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence:val avatarRenderer: AvatarRenderer
    ) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader, profilePersistence,
    avatarRenderer, userId)
    }Z
    }Y

    View Slide

  41. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: Provider,
    val profilePersistence: Provider,
    val avatarRenderer: Provider
    ) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader.get(), profilePersistence.get(),
    avatarRenderer.get(), userId)
    }Z
    }Y

    View Slide

  42. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: Provider,
    val profilePersistence: Provider,
    val avatarRenderer: Provider
    ) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader.get(), profilePersistence.get(),
    avatarRenderer.get(), userId)
    }Z
    }Y

    View Slide

  43. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: Provider,
    val profilePersistence: Provider,
    val avatarRenderer: Provider
    ) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader.get(), profilePersistence.get(),
    avatarRenderer.get(), userId)
    }Z
    }Y

    View Slide

  44. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: Provider,
    val profilePersistence: Provider,
    val avatarRenderer: Provider
    ) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader.get(), profilePersistence.get(),
    avatarRenderer.get(), userId)
    }Z
    }Y

    View Slide

  45. class ProfilePresenter {
    private final ImageLoader imageLoader;
    private final ProfilePersistence profilePersistence;
    private final AvatarRenderer avatarRenderer;
    private final String userId;
    ProfilePresenter(
    ImageLoader imageLoader, ProfilePersistence profilePersistence,
    AvatarRenderer avatarRenderer, String userId) {
    this.imageLoader = imageLoader;
    this.profilePersistence = profilePersistence;
    this.avatarRenderer = avatarRenderer;
    this.userId = userId;
    }A
    // …
    static final class Factory {
    private final Provider imageLoader;

    View Slide

  46. // …
    static final class Factory {
    private final Provider imageLoader;
    private final Provider profilePersistence;
    private final Provider avatarRenderer;
    @Inject Factory(Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) {
    this.imageLoader = imageLoader;
    this.profilePersistence = profilePersistence;
    this.avatarRenderer = avatarRenderer;
    }B
    public ProfilePresenter create(String userId) {
    return new ProfilePresenter(imageLoader.get(),
    profilePersistence.get(), avatarRenderer.get(), userId);
    }C
    }D
    }E

    View Slide

  47. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: Provider,
    val profilePersistence: Provider,
    val avatarRenderer: Provider
    )G{
    fun create(userId: String) =
    ProfilePresenter(imageLoader.get(), profilePersistence.get(),
    avatarRenderer.get(), userId)
    }Z
    }Y
    i
    n
    t
    e
    r
    f
    a
    c
    e

    View Slide

  48. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    interface FactoryG{
    fun create(userId: String): ProfilePresenter
    }Z
    }Y

    View Slide

  49. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    interface Factory {
    fun create(userId: String): ProfilePresenter
    }Z
    }Y
    install(FactoryModuleBuilder()
    .build(ProfilePresenter::class.java))

    View Slide

  50. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    interface Factory {
    fun create(userId: String): ProfilePresenter
    }Z
    }Y
    install(FactoryModuleBuilder()
    .build(ProfilePresenter::class.java))

    View Slide

  51. class ProfilePresenter @Inject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    @Assisted var userId: String
    ) {
    // …
    interface Factory {
    fun create(userId: String): ProfilePresenter
    }Z
    }Y
    install(FactoryModuleBuilder()
    .build(ProfilePresenter::class.java))

    View Slide

  52. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: Provider,
    val profilePersistence: Provider,
    val avatarRenderer: Provider
    ) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader.get(), profilePersistence.get(),
    avatarRenderer.get(), userId)
    }Z
    }Y

    View Slide

  53. @AutoFactory class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: Provider,
    val profilePersistence: Provider,
    val avatarRenderer: Provider
    ) {
    fun create(userId: String) =
    ProfilePresenter(imageLoader.get(), profilePersistence.get(),
    avatarRenderer.get(), userId)
    }Z
    }Y

    View Slide

  54. @AutoFactory class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y

    View Slide

  55. @AutoFactory class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y
    @Generated
    final class ProfilePresenterFactory {
    @Inject
    ProfilePresenterFactory(Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) { … }
    ProfilePresenter create(userId: String) { … }
    }Z

    View Slide

  56. @AutoFactory class ProfilePresenter(
    @Provided val imageLoader: ImageLoader,
    @Provided val profilePersistence: ProfilePersistence,
    @Provided val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y
    @Generated
    final class ProfilePresenterFactory {
    @Inject
    ProfilePresenterFactory(Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) { … }
    ProfilePresenter create(userId: String) { … }
    }Z

    View Slide

  57. @AutoFactory class ProfilePresenter(
    @Provided val imageLoader: ImageLoader,
    @Provided val profilePersistence: ProfilePersistence,
    @Provided val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y
    @Generated
    final class ProfilePresenterFactory {
    @Inject
    ProfilePresenterFactory(Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) { … }
    ProfilePresenter create(userId: String) { … }
    }Z

    View Slide

  58. @AutoFactory class ProfilePresenter(
    @Provided val imageLoader: ImageLoader,
    @Provided val profilePersistence: ProfilePersistence,
    @Provided val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y
    @Generated
    final class ProfilePresenterFactory {
    @Inject
    ProfilePresenterFactory(Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) { … }
    ProfilePresenter create(userId: String) { … }
    }Z

    View Slide

  59. @AutoFactory class ProfilePresenter(
    @Provided val imageLoader: ImageLoader,
    @Provided val profilePersistence: ProfilePersistence,
    @Provided val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    }Y
    @Generated
    final class ProfilePresenterFactory {
    @Inject
    ProfilePresenterFactory(Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) { … }
    ProfilePresenter create(userId: String) { … }
    }Z

    View Slide

  60. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    class Factory @Inject constructor(
    val imageLoader: Provider,
    val profilePersistence: Provider,
    val avatarRenderer: Provider
    )G{
    fun create(userId: String) =
    ProfilePresenter(imageLoader.get(), profilePersistence.get(),
    avatarRenderer.get(), userId)
    }Z
    }Y
    i
    n
    t
    e
    r
    f
    a
    c
    e

    View Slide

  61. class ProfilePresenter(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    interface FactoryG{
    fun create(userId: String): ProfilePresenter
    }Z
    }Y

    View Slide

  62. class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    var userId: String
    ) {
    // …
    interface FactoryG{
    fun create(userId: String): ProfilePresenter
    }Z
    }Y

    View Slide

  63. class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    @Assisted var userId: String
    ) {
    // …
    interface FactoryG{
    fun create(userId: String): ProfilePresenter
    }Z
    }Y

    View Slide

  64. class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    @Assisted var userId: String
    ) {
    // …
    @AssistedInject.Factory
    interface FactoryG{
    fun create(userId: String): ProfilePresenter
    }Z
    }Y

    View Slide

  65. @Generated
    class AssistedInject_ProfilePresenter implements ProfilePresenter.Factory {
    private final Provider imageLoader;
    private final Provider profilePersistence;
    private final Provider avatarRenderer;
    @Inject AssistedInject_ProfilePresenter(
    Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) {
    this.imageLoader = imageLoader;
    this.profilePersistence = profilePersistence;
    this.avatarRenderer = avatarRenderer;
    }
    @Override public ProfilePresenter create(String userId) {
    return new ProfilePresenter(imageLoader.get(),
    profilePersistence.get(), avatarRenderer.get(), userId);
    }
    }

    View Slide

  66. @Generated
    class AssistedInject_ProfilePresenter implements ProfilePresenter.Factory {
    private final Provider imageLoader;
    private final Provider profilePersistence;
    private final Provider avatarRenderer;
    @Inject AssistedInject_ProfilePresenter(
    Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) {
    this.imageLoader = imageLoader;
    this.profilePersistence = profilePersistence;
    this.avatarRenderer = avatarRenderer;
    }
    @Override public ProfilePresenter create(String userId) {
    return new ProfilePresenter(imageLoader.get(),
    profilePersistence.get(), avatarRenderer.get(), userId);
    }
    }

    View Slide

  67. @Generated
    class AssistedInject_ProfilePresenter implements ProfilePresenter.Factory {
    private final Provider imageLoader;
    private final Provider profilePersistence;
    private final Provider avatarRenderer;
    @Inject AssistedInject_ProfilePresenter(
    Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) {
    this.imageLoader = imageLoader;
    this.profilePersistence = profilePersistence;
    this.avatarRenderer = avatarRenderer;
    }
    @Override public ProfilePresenter create(String userId) {
    return new ProfilePresenter(imageLoader.get(),
    profilePersistence.get(), avatarRenderer.get(), userId);
    }
    }

    View Slide

  68. @Generated
    class AssistedInject_ProfilePresenter implements ProfilePresenter.Factory {
    private final Provider imageLoader;
    private final Provider profilePersistence;
    private final Provider avatarRenderer;
    @Inject AssistedInject_ProfilePresenter(
    Provider imageLoader,
    Provider profilePersistence,
    Provider avatarRenderer) {
    this.imageLoader = imageLoader;
    this.profilePersistence = profilePersistence;
    this.avatarRenderer = avatarRenderer;
    }
    @Override public ProfilePresenter create(String userId) {
    return new ProfilePresenter(imageLoader.get(),
    profilePersistence.get(), avatarRenderer.get(), userId);
    }
    }

    View Slide

  69. class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    @Assisted var userId: String
    ) {
    // …
    @AssistedInject.Factory
    interface Factory {
    fun create(userId: String): ProfilePresenter
    }Z
    }Y

    View Slide

  70. class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    @Assisted var userId: String
    ) {
    // …
    @AssistedInject.Factory
    interface Factory {
    fun create(userId: String): ProfilePresenter
    }Z
    }Y

    View Slide

  71. class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader,
    val profilePersistence: ProfilePersistence,
    val avatarRenderer: AvatarRenderer,
    @Assisted var userId: String
    ) {
    // …
    @AssistedInject.Factory
    interface Factory {
    fun create(userId: String): ProfilePresenter
    }Z
    }Y
    class AssistedInject_ProfilePresenter implements ProfilePresenter.Factory {
    @Inject AssistedInject_ProfilePresenter(…)
    }

    View Slide

  72. @Module
    abstract class AssistedModule {
    }S

    View Slide

  73. @Module
    abstract class AssistedModule {
    @Binds
    abstract fun bindProfilePresenterFactory(
    factory: AssistedInject_ProfilePresenter): ProfilePresenter.Factory
    }S

    View Slide

  74. @Module
    abstract class AssistedModule {
    @Binds
    abstract fun bindProfilePresenterFactory(
    factory: AssistedInject_ProfilePresenter): ProfilePresenter.Factory
    }S

    View Slide

  75. @Module
    abstract class AssistedModule {
    @Binds
    abstract fun bindProfilePresenterFactory(
    factory: AssistedInject_ProfilePresenter): ProfilePresenter.Factory
    }S

    View Slide

  76. @Module
    abstract class AssistedModule {
    @Binds
    abstract fun bindProfilePresenterFactory(
    factory: AssistedInject_ProfilePresenter): ProfilePresenter.Factory
    }S

    View Slide

  77. @Module
    abstract class AssistedModule {
    @Binds
    abstract fun bindProfilePresenterFactory(
    factory: AssistedInject_ProfilePresenter): ProfilePresenter.Factory
    }S
    @Component(modules = [PresenterModule::class])
    interface PresenterComponent {
    // …
    }T

    View Slide

  78. @Module
    abstract class AssistedModule {
    @Binds
    abstract fun bindProfilePresenterFactory(
    factory: AssistedInject_ProfilePresenter): ProfilePresenter.Factory
    }S
    @Component(modules = [PresenterModule::class, AssistedModule::class])
    interface PresenterComponent {
    // …
    }T

    View Slide

  79. @Module
    object PresenterModule {
    @JvmStatic @Provides
    fun thing() = Thing("API key")
    }H

    View Slide

  80. @AssistedModule
    @Module
    object PresenterModule {
    @JvmStatic @Provides
    fun thing() = Thing("API key")
    }H

    View Slide

  81. @AssistedModule
    @Module
    object PresenterModule {
    @JvmStatic @Provides
    fun thing() = Thing("API key")
    }H
    @Module
    @Generated
    abstract class AssistedModule_PresenterModule {
    @Binds
    abstract ProfilePresenter.Factory bindProfilePresenterFactory(
    AssistedInject_ProfilePresenter factory)
    }S

    View Slide

  82. @AssistedModule
    @Module(includes = [AssistedModule_PresenterModule::class])
    object PresenterModule {
    @JvmStatic @Provides
    fun thing() = Thing("API key")
    }H
    @Module
    @Generated
    abstract class AssistedModule_PresenterModule {
    @Binds
    abstract ProfilePresenter.Factory bindProfilePresenterFactory(
    AssistedInject_ProfilePresenter factory)
    }S

    View Slide

  83. @AssistedModule
    @Module(includes = [AssistedModule_PresenterModule::class])
    object PresenterModule {
    @JvmStatic @Provides
    fun thing() = Thing("API key")
    }H
    @Module
    @Generated
    abstract class AssistedModule_PresenterModule {
    @Binds
    abstract ProfilePresenter.Factory bindProfilePresenterFactory(
    AssistedInject_ProfilePresenter factory)
    // …
    }S

    View Slide

  84. class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }C
    }B

    View Slide

  85. class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }C
    }B

    View Slide

  86. class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }C
    }B

    View Slide

  87. class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }C
    }B
    @Module
    abstract class MainActivityModule {
    }A

    View Slide

  88. class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }C
    }B
    @Module
    abstract class MainActivityModule {
    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity
    }A

    View Slide

  89. class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }C
    }B
    @Module
    abstract class MainActivityModule {
    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity
    }A
    @Component(modules = [MainActivityModule::class])
    interface AppComponent

    View Slide

  90. class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }C
    }B
    @Module
    abstract class MainActivityModule {
    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity
    }A
    @Component(modules = [MainActivityModule::class])
    interface AppComponent
    @Module
    abstract class MainActivityModule_ContributeMainActivity { … }

    View Slide

  91. class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }C
    }B
    @Module
    abstract class MainActivityModule {
    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity
    }A
    @Component(modules = [MainActivityModule::class])
    interface AppComponent
    @Module
    abstract class MainActivityModule_ContributeMainActivity { … }

    View Slide

  92. View Slide

  93. View Slide

  94. dependencies {
    compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.0'
    kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.0'
    }A

    View Slide

  95. dependencies {
    compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.0'
    kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.0'
    // or 'annotationProcessor'…
    }A

    View Slide

  96. class ProfileView(context: Context, attrs: AttributeSet)
    : ConstraintLayout(context, attrs) {
    }Z

    View Slide

  97. class ProfileView(context: Context, attrs: AttributeSet)
    : ConstraintLayout(context, attrs) {
    lateinit var imageLoader: ImageLoader
    lateinit var avatarRenderer: AvatarRenderer
    }Z

    View Slide

  98. class ProfileView(context: Context, attrs: AttributeSet)
    : ConstraintLayout(context, attrs) {
    lateinit var imageLoader: ImageLoader
    lateinit var avatarRenderer: AvatarRenderer
    fun showProfile(profile: Profile) {
    // Use avatarRenderer…
    // Use imageLoader…
    }Y
    }Z

    View Slide

  99. class ProfileView(context: Context, attrs: AttributeSet)
    : ConstraintLayout(context, attrs) {
    lateinit var imageLoader: ImageLoader
    lateinit var avatarRenderer: AvatarRenderer
    fun showProfile(profile: Profile) {
    // Use avatarRenderer…
    // Use imageLoader…
    }Y
    }Z
    class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader, val avatarRenderer: AvatarRenderer, /*…*/
    ) {
    }I

    View Slide

  100. class ProfileView(context: Context, attrs: AttributeSet)
    : ConstraintLayout(context, attrs) {
    lateinit var imageLoader: ImageLoader
    lateinit var avatarRenderer: AvatarRenderer
    fun showProfile(profile: Profile) {
    // Use avatarRenderer…
    // Use imageLoader…
    }Y
    }Z
    class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader, val avatarRenderer: AvatarRenderer, /*…*/
    ) {
    fun attachView(view: ProfileView) {
    }W
    }I

    View Slide

  101. l
    l
    class ProfileView(context: Context, attrs: AttributeSet)G
    : ConstraintLayout(context, attrs) {
    lateinit var imageLoader: ImageLoader
    lateinit var avatarRenderer: AvatarRenderer
    fun showProfile(profile: Profile) {
    // Use avatarRenderer…
    // Use imageLoader…
    }Y
    }Z
    class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader, val avatarRenderer: AvatarRenderer, /*…*/
    ) {
    fun attachView(view: ProfileView) {
    view.imageLoader = imageLoader
    view.avatarRenderer = avatarRenderer
    }W
    }I

    View Slide

  102. r
    r
    class ProfileView(
    context: Context, attrs: AttributeSet,
    val imageLoader: ImageLoader,
    val avatarRenderer: AvatarRenderer
    )G: ConstraintLayout(context, attrs) {
    fun showProfile(profile: Profile) {
    // Use avatarRenderer…
    // Use imageLoader…
    }Y
    }Z
    class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader, val avatarRenderer: AvatarRenderer, /*…*/
    ) {
    fun attachView(view: ProfileView) {
    view.imageLoader = imageLoader
    view.avatarRenderer = avatarRenderer
    }W
    }I

    View Slide

  103. class ProfileView(
    context: Context, attrs: AttributeSet,
    val imageLoader: ImageLoader,
    val avatarRenderer: AvatarRenderer
    )G: ConstraintLayout(context, attrs) {
    fun showProfile(profile: Profile) {
    // Use avatarRenderer…
    // Use imageLoader…
    }Y
    }Z
    class ProfilePresenter @AssistedInject constructor(
    val imageLoader: ImageLoader, val avatarRenderer: AvatarRenderer, /*…*/
    ) {
    fun attachView(view: ProfileView) {
    }W
    }I

    View Slide

  104. class ProfileView(
    context: Context, attrs: AttributeSet,
    val imageLoader: ImageLoader,
    val avatarRenderer: AvatarRenderer
    )G: ConstraintLayout(context, attrs) {
    fun showProfile(profile: Profile) {
    // Use avatarRenderer…
    // Use imageLoader…
    }Y
    }Z
    class ProfilePresenter @AssistedInject constructor(/*…*/) {
    fun attachView(view: ProfileView) {
    }W
    }I

    View Slide

  105. class ProfileView(
    context: Context, attrs: AttributeSet,
    val imageLoader: ImageLoader,
    val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    fun showProfile(profile: Profile) {
    // Use avatarRenderer…
    // Use imageLoader…
    }Y
    }Z
    class ProfilePresenter @AssistedInject constructor(/*…*/) {
    fun attachView(view: ProfileView) {
    }W
    }I

    View Slide

  106. class LayoutInflater {
    }A

    View Slide

  107. class LayoutInflater {
    interface Factory {
    }B
    }A

    View Slide

  108. class LayoutInflater {
    interface Factory {
    @Nullable
    View onCreateView(
    @NonNull String name,
    @NonNull Context context,
    @NonNull AttributeSet attrs);
    }B
    }A

    View Slide

  109. class LayoutInflater {
    interface Factory {
    @Nullable
    View onCreateView(
    @NonNull String name,
    @NonNull Context context,
    @NonNull AttributeSet attrs);
    }B
    }A
    class MyAppFactory : LayoutInflater.Factory {
    }P

    View Slide

  110. class LayoutInflater {
    interface Factory {
    @Nullable
    View onCreateView(
    @NonNull String name,
    @NonNull Context context,
    @NonNull AttributeSet attrs);
    }B
    }A
    class MyAppFactory : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    }O
    }P

    View Slide

  111. class LayoutInflater {
    interface Factory {
    @Nullable
    View onCreateView(
    @NonNull String name,
    @NonNull Context context,
    @NonNull AttributeSet attrs);
    }B
    }A
    class MyAppFactory : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    if (name == ProfileView::class.java.name) {
    return TODO()
    }I
    }O
    }P

    View Slide

  112. class LayoutInflater {
    interface Factory {
    @Nullable
    View onCreateView(
    @NonNull String name,
    @NonNull Context context,
    @NonNull AttributeSet attrs);
    }B
    }A
    class MyAppFactory : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    if (name == ProfileView::class.java.name) {
    return TODO()
    }I
    return null
    }O
    }P

    View Slide

  113. class ProfileView(
    context: Context, attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    }Z

    View Slide

  114. class ProfileView(G
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    }Z

    View Slide

  115. class ProfileView @AssistedInject constructor(G
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    }Z

    View Slide

  116. class ProfileView @AssistedInject constructor(G
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    @AssistedInject.Factory
    interface Factory {
    fun create(context: Context, attrs: AttributeSet): ProfileView
    }G
    }Z

    View Slide

  117. class MyAppFactory : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    if (name == ProfileView::class.java.name) {
    return TODO()
    }I
    return null
    }O
    }P

    View Slide

  118. class MyAppFactory @Inject constructor() : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    if (name == ProfileView::class.java.name) {
    return TODO()
    }I
    return null
    }O
    }P

    View Slide

  119. class MyAppFactory @Inject constructor(
    private val profileViewFactory: ProfileView.Factory
    ) : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    if (name == ProfileView::class.java.name) {
    return TODO()
    }I
    return null
    }O
    }P

    View Slide

  120. class MyAppFactory @Inject constructor(
    private val profileViewFactory: ProfileView.Factory
    ) : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    if (name == ProfileView::class.java.name) {
    return profileViewFactory.create(context, attrs)
    }I
    return null
    }O
    }P

    View Slide

  121. class MyAppFactory @Inject constructor(
    private val profileViewFactory: ProfileView.Factory,
    private val cartViewFactory: CartView.Factory
    ) : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    if (name == ProfileView::class.java.name) {
    return profileViewFactory.create(context, attrs)
    }I
    if (name == CartView::class.java.name) {
    return cartViewFactory.create(context, attrs)
    }I
    return null
    }O
    }P

    View Slide

  122. class MyAppFactory @Inject constructor(
    private val profileViewFactory: ProfileView.Factory,
    private val cartViewFactory: CartView.Factory,
    private val checkoutViewFactory: CheckoutView.Factory
    ) : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    if (name == ProfileView::class.java.name) {
    return profileViewFactory.create(context, attrs)
    }I
    if (name == CartView::class.java.name) {
    return cartViewFactory.create(context, attrs)
    }I
    if (name == CheckoutView::class.java.name) {
    return checkoutViewFactory.create(context, attrs)
    }I
    return null
    }O
    }P

    View Slide

  123. class MyAppFactory @Inject constructor(
    private val viewFactories: Map
    ) : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    if (name == ProfileView::class.java.name) {
    return profileViewFactory.create(context, attrs)
    }I
    if (name == CartView::class.java.name) {
    return cartViewFactory.create(context, attrs)
    }I
    if (name == CheckoutView::class.java.name) {
    return checkoutViewFactory.create(context, attrs)
    }I
    return null
    }O
    }P
    private val profileViewFactory: ProfileView.Factory,
    private val cartViewFactory: CartView.Factory,
    private val checkoutViewFactory: CheckoutView.Factory

    View Slide

  124. class MyAppFactory @Inject constructor(
    private val viewFactories: Map
    ) : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    return viewFactories[name]?.create(context, attrs)
    }O
    }P
    if (name == ProfileView::class.java.name) {
    return profileViewFactory.create(context, attrs)
    }I
    if (name == CartView::class.java.name) {
    return cartViewFactory.create(context, attrs)
    }I
    if (name == CheckoutView::class.java.name) {
    return checkoutViewFactory.create(context, attrs)
    }I null

    View Slide

  125. class MyAppFactory @Inject constructor(
    private val viewFactories: Map
    ) : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    return viewFactories[name]?.create(context, attrs)
    }O
    }P
    interface ViewFactory {
    fun create(context: Context, attrs: AttributeSet): View
    }

    View Slide

  126. class ProfileView @AssistedInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    @AssistedInject.Factory
    interface Factory {A
    fun create(context: Context, attrs: AttributeSet): ProfileView
    }G
    }Z

    View Slide

  127. class ProfileView @AssistedInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    @AssistedInject.Factory
    interface Factory : ViewFactory {A
    override fun create(context: Context, attrs: AttributeSet): ProfileView
    }G
    }Z

    View Slide

  128. class ProfileView @AssistedInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    @AssistedInject.Factory
    interface Factory : ViewFactory {
    override fun create(context: Context, attrs: AttributeSet): ProfileView
    }G
    }Z
    @Module
    abstract class ViewModule {
    }Q

    View Slide

  129. class ProfileView @AssistedInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    @AssistedInject.Factory
    interface Factory : ViewFactory {
    override fun create(context: Context, attrs: AttributeSet): ProfileView
    }G
    }Z
    @Module
    abstract class ViewModule {
    @Binds
    abstract fun profileView(factory: ProfileView.Factory): ViewFactory
    }Q

    View Slide

  130. class ProfileView @AssistedInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    @AssistedInject.Factory
    interface Factory : ViewFactory {
    override fun create(context: Context, attrs: AttributeSet): ProfileView
    }G
    }Z
    @Module
    abstract class ViewModule {
    @Binds
    @IntoMap
    abstract fun profileView(factory: ProfileView.Factory): ViewFactory
    }Q

    View Slide

  131. class ProfileView @AssistedInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    @AssistedInject.Factory
    interface Factory : ViewFactory {
    override fun create(context: Context, attrs: AttributeSet): ProfileView
    }G
    }Z
    @Module
    abstract class ViewModule {
    @Binds
    @IntoMap
    @StringKey("com.example.ProfileView")
    abstract fun profileView(factory: ProfileView.Factory): ViewFactory
    }Q

    View Slide

  132. class ProfileView @AssistedInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    @AssistedInject.Factory
    interface Factory : ViewFactory {
    override fun create(context: Context, attrs: AttributeSet): ProfileView
    }G
    }Z
    @Module
    abstract class ViewModule {
    @Binds
    @IntoMap
    @StringKey("com.example.ProfileView")
    abstract fun profileView(factory: ProfileView.Factory): ViewFactory
    }Q

    View Slide

  133. class ProfileView @AssistedInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    @AssistedInject.Factory
    interface Factory : ViewFactory {
    override fun create(context: Context, attrs: AttributeSet): ProfileView
    }G
    }Z
    @Module
    abstract class ViewModule {
    @Binds
    @IntoMap
    @StringKey("com.example.ProfileView")
    abstract fun profileView(factory: ProfileView.Factory): ViewFactory
    }Q

    View Slide

  134. class ProfileView @AssistedInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    // …
    }Z

    View Slide

  135. class ProfileView @InflationInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    // …
    }Z
    @Assisted

    View Slide

  136. class ProfileView @InflationInject constructor(
    @Assisted context: Context, @Assisted attrs: AttributeSet,
    private val imageLoader: ImageLoader,
    private val avatarRenderer: AvatarRenderer
    ) : ConstraintLayout(context, attrs) {
    // …
    }Z

    View Slide

  137. @Generated
    class InflationInject_ProfileView implements ViewFactory {
    private final Provider imageLoader;
    private final Provider avatarRenderer;
    @Inject InflationInject_ProfileView(
    Provider imageLoader,
    Provider avatarRenderer) {
    this.imageLoader = imageLoader;
    this.avatarRenderer = avatarRenderer;
    }
    @Override public View create(Context context, AttributeSet attrs) {
    return new ProfileView(
    context, attrs, imageLoader.get(), avatarRenderer.get());
    }
    }

    View Slide

  138. @Generated
    class InflationInject_ProfileView implements ViewFactory {
    private final Provider imageLoader;
    private final Provider avatarRenderer;
    @Inject InflationInject_ProfileView(
    Provider imageLoader,
    Provider avatarRenderer) {
    this.imageLoader = imageLoader;
    this.avatarRenderer = avatarRenderer;
    }
    @Override public View create(Context context, AttributeSet attrs) {
    return new ProfileView(
    context, attrs, imageLoader.get(), avatarRenderer.get());
    }
    }

    View Slide

  139. @Generated
    class InflationInject_ProfileView implements ViewFactory {
    private final Provider imageLoader;
    private final Provider avatarRenderer;
    @Inject InflationInject_ProfileView(
    Provider imageLoader,
    Provider avatarRenderer) {
    this.imageLoader = imageLoader;
    this.avatarRenderer = avatarRenderer;
    }
    @Override public View create(Context context, AttributeSet attrs) {
    return new ProfileView(
    context, attrs, imageLoader.get(), avatarRenderer.get());
    }
    }

    View Slide

  140. @Module
    object ViewModule {
    }H

    View Slide

  141. @InflationModule
    @Module
    object ViewModule {
    }H

    View Slide

  142. @InflationModule
    @Module
    object ViewModule {
    }H
    @Module
    @Generated
    abstract class InflationModule_ViewModule {
    @Binds
    @IntoMap
    @StringKey("com.example.ProfileView")
    abstract ViewFactory bindProfileView(
    InflationInject_ProfileView factory)
    }S

    View Slide

  143. @InflationModule
    @Module(includes = [InflationModule_ViewModule::class])
    object ViewModule {
    }H
    @Module
    @Generated
    abstract class InflationModule_ViewModule {
    @Binds
    @IntoMap
    @StringKey("com.example.ProfileView")
    abstract ViewFactory bindProfileView(
    InflationInject_ProfileView factory)
    }S

    View Slide

  144. @InflationModule
    @Module(includes = [InflationModule_ViewModule::class])
    object ViewModule {
    }H
    @Module
    @Generated
    abstract class InflationModule_ViewModule {
    @Binds
    @IntoMap
    @StringKey("com.example.ProfileView")
    abstract ViewFactory bindProfileView(
    InflationInject_ProfileView factory)
    // …
    }S

    View Slide

  145. class MyAppFactory @Inject constructor(
    private val viewFactories: Map
    ) : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    return viewFactories[name]?.create(context, attrs)
    }O
    }P

    View Slide

  146. class InflationInjectFactory @Inject constructor(
    private val viewFactories: Map
    ) : LayoutInflater.Factory {
    override fun onCreateView(name: String,
    context: Context, attrs: AttributeSet): View? {
    return viewFactories[name]?.create(context, attrs)
    }O
    }P

    View Slide

  147. class ProfileActivity : Activity() {
    }A

    View Slide

  148. class ProfileActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }B
    }A

    View Slide

  149. class ProfileActivity : Activity() {
    @Inject lateinit var presenterFactory: ProfilePresenter.Factory
    @Inject lateinit var inflationFactory: InflationInjectFactory
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    }B
    }A

    View Slide

  150. class ProfileActivity : Activity() {
    @Inject lateinit var presenterFactory: ProfilePresenter.Factory
    @Inject lateinit var inflationFactory: InflationInjectFactory
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    layoutInflater.factory = inflationFactory
    }B
    }A

    View Slide

  151. class ProfileActivity : Activity() {
    @Inject lateinit var presenterFactory: ProfilePresenter.Factory
    @Inject lateinit var inflationFactory: InflationInjectFactory
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    layoutInflater.factory = inflationFactory
    setContentView(R.layout.profile_view)
    }B
    }A

    View Slide

  152. class ProfileActivity : Activity() {
    @Inject lateinit var presenterFactory: ProfilePresenter.Factory
    @Inject lateinit var inflationFactory: InflationInjectFactory
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    layoutInflater.factory = inflationFactory
    setContentView(R.layout.profile_view)
    val userId = intent.getStringExtra("userId")
    val presenter = presenterFactory.create(userId)
    presenter.attachView(findViewById(R.id.profile_view)
    }B
    }A

    View Slide

  153. class ProfileActivity : Activity() {
    @Inject lateinit var presenterFactory: ProfilePresenter.Factory
    @Inject lateinit var inflationFactory: InflationInjectFactory
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    layoutInflater.factory = inflationFactory
    setContentView(R.layout.profile_view)
    val userId = intent.getStringExtra("userId")
    val presenter = presenterFactory.create(userId)
    presenter.attachView(findViewById(R.id.profile_view)
    }B
    }A
    l
    l

    View Slide

  154. class ProfileActivity @Inject constructor(
    val presenterFactory: ProfilePresenter.Factory
    val inflationFactory: InflationInjectFactory
    : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    AndroidInjection.inject(this)
    layoutInflater.factory = inflationFactory
    setContentView(R.layout.profile_view)
    val userId = intent.getStringExtra("userId")
    val presenter = presenterFactory.create(userId)
    presenter.attachView(findViewById(R.id.profile_view)
    }B
    }A
    @
    I
    n
    j
    e
    c
    t l
    a
    t
    e
    i
    n
    i
    t r
    @
    I
    n
    j
    e
    c
    t l
    a
    t
    e
    i
    n
    i
    t r

    View Slide

  155. View Slide

  156. View Slide

  157. View Slide

  158. dependencies {
    compileOnly 'com.squareup.inject:inflation-inject:0.3.0'
    kapt 'com.squareup.inject:inflation-inject-processor:0.3.0'
    }A

    View Slide

  159. dependencies {
    compileOnly 'com.squareup.inject:inflation-inject:0.3.0'
    kapt 'com.squareup.inject:inflation-inject-processor:0.3.0'
    // or 'annotationProcessor'…
    }A

    View Slide

  160. View Slide

  161. View Slide

  162. View Slide

  163. View Slide

  164. View Slide

  165. View Slide

  166. allprojects {
    }A

    View Slide

  167. allprojects {
    tasks.withType(JavaCompile).all {
    }B
    }A

    View Slide

  168. allprojects {
    tasks.withType(JavaCompile).all {
    options.compilerArgs += []C
    }B
    }A

    View Slide

  169. allprojects {
    tasks.withType(JavaCompile).all {
    options.compilerArgs += [
    '-Adagger.formatGeneratedSource=disabled'
    ]C
    }B
    }A

    View Slide

  170. allprojects {
    tasks.withType(JavaCompile).all {
    options.compilerArgs += [
    '-Adagger.formatGeneratedSource=disabled'
    ]C
    }B
    afterEvaluate {
    extensions.findByName('kapt')?.arguments {
    arg("dagger.formatGeneratedSource", "disabled")
    }D
    }C
    }A

    View Slide

  171. View Slide

  172. allprojects {
    tasks.withType(JavaCompile).all {
    options.compilerArgs += [
    '-Adagger.formatGeneratedSource=disabled'
    ]C
    }B
    afterEvaluate {
    extensions.findByName('kapt')?.arguments {
    arg("dagger.formatGeneratedSource", "disabled")
    }D
    }C
    }A

    View Slide

  173. allprojects {
    tasks.withType(JavaCompile).all {
    options.compilerArgs += [
    '-Adagger.formatGeneratedSource=disabled',
    '-Adagger.gradle.incremental=enabled'
    ]C
    }B
    afterEvaluate {
    extensions.findByName('kapt')?.arguments {
    arg("dagger.formatGeneratedSource", "disabled")
    arg("dagger.gradle.incremental", "enabled")
    }D
    }C
    }A

    View Slide

  174. View Slide

  175. View Slide

  176. View Slide

  177. View Slide

  178. View Slide

  179. View Slide

  180. View Slide

  181. View Slide

  182. View Slide

  183. ButterKnife.bind(this)

    View Slide

  184. ButterKnife.bind(this)
    class ButterKnife {
    static Unbinder bind(Activity target) {
    // Class.forName lookup…
    }
    }
    butterknife-runtime.aar

    View Slide

  185. ButterKnife.bind(this)
    class ButterKnife {
    static Unbinder bind(Activity target) {
    // Reflection implementation…
    }
    }
    butterknife-reflect.aar
    class ButterKnife {
    static Unbinder bind(Activity target) {
    // Class.forName lookup…
    }
    }
    butterknife-runtime.aar

    View Slide

  186. dependencies {
    if (properties.containsKey('android.injected.invoked.from.ide')) {
    implementation 'com.jakewharton:butterknife-reflect:9.0.0-rc1'
    } else {
    implementation 'com.jakewharton:butterknife:9.0.0-rc1'
    kapt 'com.jakewharton:butterknife-compiler:9.0.0-rc1'
    }B
    }A

    View Slide

  187. dependencies {
    if (properties.containsKey('android.injected.invoked.from.ide')) {
    implementation 'com.jakewharton:butterknife-reflect:9.0.0-rc1'
    } else {
    implementation 'com.jakewharton:butterknife:9.0.0-rc1'
    kapt 'com.jakewharton:butterknife-compiler:9.0.0-rc1'
    // or 'annotationProcessor'…
    }B
    }A

    View Slide

  188. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A

    View Slide

  189. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A
    val component = DaggerAppComponent.builder()
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  190. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A
    val component = DaggerAppComponent.builder()
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  191. class DaggerReflect {
    }A

    View Slide

  192. class DaggerReflect {
    static B builder(Class builderClass) {
    }B
    }A

    View Slide

  193. class DaggerReflect {C
    static B builder(Class builderClass) {
    return (B) Proxy.newProxyInstance(
    builderClass.getClassLoader(),
    new Class[] { builderClass },
    ComponentBuilderInvocationHandler.create(builderClass));
    }B
    }A

    View Slide

  194. class DaggerReflect {C
    static B builder(Class builderClass) {
    return (B) Proxy.newProxyInstance(
    builderClass.getClassLoader(),
    new Class[] { builderClass },
    ComponentBuilderInvocationHandler.create(builderClass));
    }B
    }A

    View Slide

  195. class DaggerReflect {C
    static B builder(Class builderClass) {
    return (B) Proxy.newProxyInstance(
    builderClass.getClassLoader(),
    new Class[] { builderClass },
    ComponentBuilderInvocationHandler.create(builderClass));
    }B
    }A

    View Slide

  196. class DaggerReflect {
    static C create(Class componentClass) {
    return (C) Proxy.newProxyInstance(
    componentClass.getClassLoader(),
    new Class[] { componentClass },
    ComponentInvocationHandler.create(componentClass));
    }C
    static B builder(Class builderClass) {
    return (B) Proxy.newProxyInstance(
    builderClass.getClassLoader(),
    new Class[] { builderClass },
    ComponentBuilderInvocationHandler.create(builderClass));
    }B
    }A

    View Slide

  197. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A
    val component = DaggerAppComponent.builder()
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  198. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A
    val component = DaggerAppComponent.builder()
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  199. final class DaggerAppComponent {
    }A

    View Slide

  200. final class DaggerAppComponent {
    static AppComponent.Builder builder() {
    return DaggerReflect.builder(AppComponent.Builder.class);
    }B
    }A

    View Slide

  201. final class DaggerAppComponent {
    static AppComponent create() {
    return DaggerReflect.create(AppComponent.class);
    }C
    static AppComponent.Builder builder() {
    return DaggerReflect.builder(AppComponent.Builder.class);
    }B
    }A

    View Slide

  202. DaggerAppComponent.builder()

    View Slide

  203. DaggerAppComponent.builder()
    final class DaggerAppComponent {
    static AppComponent.Builder builder() {
    // real Dagger implementation…
    }B
    }A
    dagger-compiler.jar + dagger.jar

    View Slide

  204. DaggerAppComponent.builder()
    final class DaggerAppComponent {
    static AppComponent.Builder builder() {
    return DaggerReflect.builder(
    AppComponent.Builder.class);
    }B
    }A
    dagger-reflect.jar
    final class DaggerAppComponent {
    static AppComponent.Builder builder() {
    // real Dagger implementation…
    }B
    }A
    dagger-compiler.jar + dagger.jar

    View Slide

  205. dagger-compiler.jar
    dagger.jar
    dagger-reflect.jar

    View Slide

  206. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A
    val component = DaggerAppComponent.builder()
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  207. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A
    val component = DaggerReflect.builder(AppComponent.Builder::class)
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  208. class Dagger {
    }A

    View Slide

  209. class Dagger {
    static B builder(Class builderClass) {
    }B
    }A

    View Slide

  210. class Dagger {
    static B builder(Class builderClass) {
    return DaggerReflect.builder(builderClass);
    }B
    }A

    View Slide

  211. class Dagger {
    static B builder(Class builderClass) {
    return DaggerReflect.builder(builderClass);
    }B
    }A
    class Dagger {
    }A

    View Slide

  212. class Dagger {
    static B builder(Class builderClass) {
    return DaggerReflect.builder(builderClass);
    }B
    }A
    class Dagger {
    static B builder(Class builderClass) {
    }B
    }A

    View Slide

  213. class Dagger {
    static B builder(Class builderClass) {
    return DaggerReflect.builder(builderClass);
    }B
    }A
    class Dagger {
    static B builder(Class builderClass) {
    return builderClass.getMethod("builder").invoke(null);
    }B
    }A

    View Slide

  214. class Dagger {
    static B builder(Class builderClass) {
    return DaggerReflect.builder(builderClass);
    }B
    }A
    class Dagger {
    static B builder(Class builderClass) {
    return builderClass.getMethod("builder").invoke(null);
    }B
    }A
    dagger-reflect.jar
    dagger-codegen.jar

    View Slide

  215. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A
    val component = DaggerReflect.builder(AppComponent.Builder::class)
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  216. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A
    val component = Dagger.builder(AppComponent.Builder::class)
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  217. @Component(modules = [AppModule::class])
    interface AppComponent {
    fun foo(): Foo
    fun bar(): Bar
    fun thermosiphon(): Thermosiphon
    @Component.Builder
    interface Builder {
    @BindsInstance fun apiKey(@ApiKey apiKey: String)
    fun build(): AppComponent
    }B
    }A
    val component = Dagger.builder(AppComponent.Builder::class)
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  218. val component = Dagger.builder(AppComponent.Builder::class)G
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  219. val component = AppComponent.Builder::class.builder()G
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()

    View Slide

  220. val component = AppComponent.Builder::class.builder()G
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()
    // dagger-reflect:
    inline fun KClass.builder(): B = DaggerReflect.builder(java)

    View Slide

  221. val component = AppComponent.Builder::class.builder()G
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()
    // dagger-reflect:
    inline fun KClass.builder(): B = DaggerReflect.builder(java)
    // dagger-codegen:
    inline fun KClass.builder(): B =
    throw UnsupportedOperationException("…")

    View Slide

  222. val component = AppComponent.Builder::class.builder()G
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()
    // dagger-reflect:
    inline fun KClass.builder(): B = DaggerReflect.builder(java)
    // dagger-codegen:
    inline fun KClass.builder(): B =
    throw UnsupportedOperationException("…")
    // Generated from dagger-codegen-compiler:
    @JvmName("builderAppComponent")
    inline fun KClass.builder() = AppComponent.builder()

    View Slide

  223. val component = AppComponent.Builder::class.builder()G
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()
    // dagger-reflect:
    inline fun KClass.builder(): B = DaggerReflect.builder(java)
    // dagger-codegen:
    inline fun KClass.builder(): B =
    throw UnsupportedOperationException("…")
    // Generated from dagger-codegen-compiler:
    @JvmName("builderAppComponent")
    inline fun KClass.builder() = AppComponent.builder()

    View Slide

  224. AppComponent.Builder::class.builder()G
    val component =
    .apiKey("IDt0n5RoTAc0l3CiVR3sRn13d0kdNaN1oK")
    .build()
    // dagger-reflect:
    inline fun KClass.builder(): B = DaggerReflect.builder(java)
    // dagger-codegen:
    inline fun KClass.builder(): B =
    throw UnsupportedOperationException("…")
    // Generated from dagger-codegen-compiler:
    @JvmName("builderAppComponent")
    inline fun KClass.builder() = AppComponent.builder()
    AppComponent.builder()

    View Slide

  225. View Slide

  226. View Slide

  227. Helping
    Dagger
    Help
    You
    @JakeWharton

    View Slide