Touching motif - DI library for Android and Java applications

Touching motif - DI library for Android and Java applications

I have talked about uber/motif library which provides simple API for dependency injection at potatotips#54.

uber/motif: A simple DI API for Android / Java
https://github.com/uber/motif

F9856cc7a15ed2cb9e6ebfab41fdf1cf?s=128

Shohei Kawano

August 23, 2018
Tweet

Transcript

  1. uber/motif @shaunkawano

  2. •DI library - simple API optimized for nested scopes •Generates

    Dagger code for actual DI •Under heavily development uber/motif
  3. None
  4. Usage

  5. @motif.Scope interface AppScope { @motif.Objects abstract class Objects { fun

    okHttpClient(): OkHttpClient = 
 OkHttpClient.Builder().build() fun retrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder().client(okHttpClient).baseUrl("") .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) .build() fun service(retrofit: Retrofit): Service = retrofit.create(Service::class.java) fun api(service: Service): Api = ApiClient(service) } }
  6. @motif.Scope interface AppScope { @motif.Objects abstract class Objects { fun

    okHttpClient(): OkHttpClient = 
 OkHttpClient.Builder().build() fun retrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder().client(okHttpClient).baseUrl("") .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) .build() fun service(retrofit: Retrofit): Service = retrofit.create(Service::class.java) fun api(service: Service): Api = ApiClient(service) } }
  7. @motif.Scope interface AppScope { @motif.Objects abstract class Objects { fun

    okHttpClient(): OkHttpClient = 
 OkHttpClient.Builder().build() fun retrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder().client(okHttpClient).baseUrl("") .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) .build() fun service(retrofit: Retrofit): Service = retrofit.create(Service::class.java) fun api(service: Service): Api = ApiClient(service) } }
  8. @motif.Scope interface AppScope { @motif.Objects abstract class Objects { fun

    okHttpClient(): OkHttpClient = 
 OkHttpClient.Builder().build() fun retrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder().client(okHttpClient).baseUrl("") .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) .build() fun service(retrofit: Retrofit): Service = retrofit.create(Service::class.java) fun api(service: Service): Api = ApiClient(service) } }
  9. None
  10. None
  11. public class AppScopeImpl implements AppScope { private final Component component;

    public AppScopeImpl(Dependencies dependencies) { this.component = DaggerAppScopeImpl_Component.builder() .dependencies(dependencies) .module(new Module()) .build(); } public AppScopeImpl() { this(new Dependencies() {}); } public interface Dependencies { } @DaggerScope @dagger.Component( dependencies = Dependencies.class, modules = Module.class ) interface Component { } private static class Objects extends AppScope.Objects { } …
  12. @dagger.Module class Module { private final AppScope.Objects objects = new

    Objects(); @Provides AppScope appScope() { return AppScopeImpl.this; } @Provides @DaggerScope OkHttpClient okHttpClient() { return objects.okHttpClient(); } @Provides @DaggerScope Retrofit retrofit(OkHttpClient okHttpClient) { return objects.retrofit(okHttpClient); } @Provides @DaggerScope Service service(Retrofit retrofit) { return objects.service(retrofit); } … }
  13. None
  14. public final class AppScopeImpl_Module_ApiFactory implements Factory<Api> { private final AppScopeImpl.Module

    module; private final Provider<Service> serviceProvider; public AppScopeImpl_Module_ApiFactory( AppScopeImpl.Module module, Provider<Service> serviceProvider) { this.module = module; this.serviceProvider = serviceProvider; } @Override public Api get() { return provideInstance(module, serviceProvider); } public static Api provideInstance(AppScopeImpl.Module module, Provider<Service> serviceProvider) { return proxyApi(module, serviceProvider.get()); } … public static Api proxyApi(AppScopeImpl.Module instance, Service service) { return Preconditions.checkNotNull( instance.api(service), "Cannot return null from a non-@Nullable @Provides method"); } }
  15. It generates code similar to or the same as what

    dagger generates
  16. dagger & motif?

  17. # of concepts

  18. @RootComponent.Scope @Component(modules = RootComponent.Module.class) public interface RootComponent { RootController controller();

    LoggedInComponent.Builder loggedIn(); @dagger.Component.Builder interface Builder { @BindsInstance Builder viewGroup(@Root ViewGroup parent); RootComponent build(); } @dagger.Module abstract class Module { @Scope @Provides static RootView view(@Root ViewGroup parent) { return RootView.create(parent); } } @javax.inject.Scope @interface Scope {} @Qualifier @interface Root {} }
  19. @RootComponent.Scope @Component(modules = RootComponent.Module.class) public interface RootComponent { RootController controller();

    LoggedInComponent.Builder loggedIn(); @dagger.Component.Builder interface Builder { @BindsInstance Builder viewGroup(@Root ViewGroup parent); RootComponent build(); } @dagger.Module abstract class Module { @Scope @Provides static RootView view(@Root ViewGroup parent) { return RootView.create(parent); } } @javax.inject.Scope @interface Scope {} @Qualifier @interface Root {} } •@Scope •@Component / @Subcomponent •@Component.Buidler / @Subcomponent.Builder •@Qualifier •@BindsInstance •@Module •@Provides •abstract @Modules •static @Provides •Component provision method •Component factory method •Constructor injection
  20. @Scope public interface RootScope { RootController controller(); LoggedInScope loggedIn(ViewGroup parentViewGroup);

    @motif.Objects abstract class Objects { abstract RootController controller(); RootView view(ViewGroup viewGroup) { return RootView.create(viewGroup); } } }
  21. @Scope public interface RootScope { RootController controller(); LoggedInScope loggedIn(ViewGroup parentViewGroup);

    @motif.Objects abstract class Objects { abstract RootController controller(); RootView view(ViewGroup viewGroup) { return RootView.create(viewGroup); } } } •@motif.Scope •@motif.Objects •Access method •Child method •Factory method (Basic) •Factory method (Constructor Injected)
  22. •dagger •Fully customizable •Required to understand its concepts •Code readability

    concern •motif •Less customizable •Less concepts •More readable Philosophy
  23. @Expose

  24. @motif.Scope interface ChildScope { @motif.Objects open class Objects { fun

    childService(retrofit: Retrofit): ChildService = retrofit.create(ChildService::class.java) fun childApi(childService: ChildService): ChildApi = ChildApiClient(childService) } }
  25. @motif.Scope interface ChildScope { @motif.Objects open class Objects { fun

    childService(retrofit: Retrofit): ChildService = retrofit.create(ChildService::class.java) fun childApi(childService: ChildService): ChildApi = ChildApiClient(childService) } }
  26. @motif.Scope interface AppScope { fun childScope(): ChildScope @motif.Objects open class

    Objects { fun okHttpClient(): OkHttpClient = OkHttpClient.Builder().build() fun retrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder().client(okHttpClient).baseUrl(“") .addCallAdapterFactory(RxJava2CallAdapterFactory .createAsync()).build() fun service(retrofit: Retrofit): Service = retrofit.create(Service::class.java) fun api(service: Service): Api = ApiClient(service) } }
  27. @motif.Scope interface AppScope { fun childScope(): ChildScope @motif.Objects open class

    Objects { fun okHttpClient(): OkHttpClient = OkHttpClient.Builder().build() fun retrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder().client(okHttpClient).baseUrl(“") .addCallAdapterFactory(RxJava2CallAdapterFactory .createAsync()).build() fun service(retrofit: Retrofit): Service = retrofit.create(Service::class.java) fun api(service: Service): Api = ApiClient(service) } }
  28. None
  29. @Expose

  30. @motif.Scope interface AppScope { fun childScope(): ChildScope @motif.Objects open class

    Objects { fun okHttpClient(): OkHttpClient = OkHttpClient.Builder().build() fun retrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder().client(okHttpClient).baseUrl(“") .addCallAdapterFactory(RxJava2CallAdapterFactory .createAsync()) .build() fun service(retrofit: Retrofit): Service = retrofit.create(Service::class.java) fun api(service: Service): Api = ApiClient(service) } }
  31. @motif.Scope interface AppScope { fun childScope(): ChildScope @motif.Objects open class

    Objects { fun okHttpClient(): OkHttpClient = OkHttpClient.Builder().build() @Expose fun retrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder().client(okHttpClient).baseUrl("") .addCallAdapterFactory(RxJava2CallAdapterFactory .createAsync()) .build() fun service(retrofit: Retrofit): Service = retrofit.create(Service::class.java) fun api(service: Service): Api = ApiClient(service) } }
  32. Summary

  33. •DI library •Clearly different from Dagger •Under heavily development •Read

    and understand its philosophy before choosing to use it or not uber/motif
  34. Uber/Motif @shaunkawano Thank you!