How to use Android Injector for Activity and Fragment objects through New Dagger 2 (with Kotlin)

2020-11-22 21:24:01

参考地址 参考文章 https://medium.com/@serapbercin001/how-to-use-android-injector-for-activity-and-fragment-objects-through-new-dagger-2-with-kotlin-704eb8a98c43



This article is regarding how to implement dagger 2 with new approach, It brought giant change and in this way getting ride of boilerplate code through dagger 2.x new release. However I don’t compare between old and new dagger structure so I just have developed a simple sample from scratch about that and basically touch on @Component@Module@ContributesAndroidInjectorAndroidInjection.inject(this)AndroidSupportInjection.inject(this).

If you want to use these, first of all we should set up gradle:

Set up gradle:

kapt 'com.google.dagger:dagger-compiler:2.16'
kapt 'com.google.dagger:dagger-android-processor:2.16'
implementation 'com.google.dagger:dagger-android-support:2.16'

i added kapt instead of annotationProcessor for kotlin. we dont need to keep annotationProcessor dependency. Also we have to add kotlin-plugin in gradle.

apply plugin: 'kotlin-kapt'

Basically Package Structure:


Let’s start to create ApplicationComponent interface that is root in our dagger graph. It may includes more modules that just listed here. For instance; api module, shared preference module and something like that. I started to add AndroidInjectionModule as a module in the component. This module should be installed in the component that is used to inject. AndroidInjectionModule also is internal module, it was created by Dagger, it includes binding activity, fragment, service, broadcastReciver and content provider. We will add ActivitiesModule module later on.

@Singleton
@Component(modules = AndroidInjectionModule::class)
interface ApplicationComponent {

  fun inject(application: Application)

  @Component.Builder
  interface Builder {

     fun build(): ApplicationComponent

     @BindsInstance
     fun applicationBind(application: Application): Builder

  }
}

Let’s start to write ActivitiesModule as a subcomponent, we will use @ContributesAndroidInjector annotation type. After that we will add it in ApplicationComponent as a module.

@Module
abstract class ActivitiesModule {
  @ContributesAndroidInjector(modules =    [(MainActivityModule::class)])
  abstract fun contributeActivityAndroidInjector(): MainActivity

}

@ContributesAndroidInjector can takes modules, Modules to be installed in the generated. I’ll explain the MainActiviyModule that what should include, also with @Bind annotation . By the way If module needs scope, we can create spesific Scope, for instance; @ActivityScope, @FragmentScope..

import javax.inject.Scope

@Scope
@MustBeDocumented
annotation class ActivityScope

if you need it, we can add scope like here.

@ActivityScope
@ContributesAndroidInjector(modules = [(ActivityModule::class)])
abstract fun contributeActivityAndroidInjector(): MainActivity

Dagger 2 includes HasActivityInjector as a new that provides AndroidInjector and should implement in Application class, also we should inject DispatchingAndroidInjector that’s mean return activityInjector, in this way we’ll use AndroidInjection.inject() for activity and fragment.

class SampleApplication : Application(), HasActivityInjector {

   @Inject
   lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>


   override fun onCreate() {
       super.onCreate()
       DaggerApplicationComponent.builder()
               .applicationBind(this)
               .build()
               .inject(this)

   }

   override fun activityInjector(): AndroidInjector<Activity> = dispatchingAndroidInjector

}

We can use AndroidInjection.inject(this) in activity after inject DispatchingAndroidInjector in application.

AndroidInjection.inject(this) should calls in onCreate method before super. That’s all!!

class MainActivity : AppCompatActivity(){ override fun onCreate(savedInstanceState: Bundle?) {
  AndroidInjection.inject(this)
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
}
}

you can see generated file below that code was created by dagger after rebuild. Remember, via androidInjector.inject(this) we passed activity, it gets DispatchingAndroidInjector<Activity> from application.

private DispatchingAndroidInjector<Activity> getDispatchingAndroidInjectorOfActivity() {
 return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector(
     getMapOfClassOfAndProviderOfFactoryOf());
}

DispatchingAndroidInjector looks up AndroidInjector.Factory, it is below the code snippet. it creates your activities subcomponent builder, and pass the activities to inject your activities.

private Map<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>>
   getMapOfClassOfAndProviderOfFactoryOf() {
 return MapBuilder
     .<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>>
         newMapBuilder(2)
     .put(MainActivity.class, (Provider) mainActivitySubcomponentBuilderProvider)
     .put(SecondActivity.class, (Provider) secondActivitySubcomponentBuilderProvider)
     .build();
}

Inject Fragment Object

So far, We injected Activity object.Well, How we can inject fragment object. We will modify activity class to inject fragment object and implement HasSupportFragmentInjector or HasFragmentInjector interface. HasSupportFragmentInjector is for android.support.v4.app.Fragment and HasFragmentInjector is for android.app.Fragment after that we pass fragment in DispatchingAndroidInjector, that’s looks here.

class MainActivity : AppCompatActivity(), HasSupportFragmentInjector {

  @Inject
  lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>

  override fun onCreate(savedInstanceState: Bundle?) {
     AndroidInjection.inject(this)
     super.onCreate(savedInstanceState)
     setContentView(R.layout.activity_main)
  }

  override fun supportFragmentInjector() = dispatchingAndroidInjector

}

Also, we create Fragment module same way with the activity.

@Module
abstract class FragmentModule {

  @ContributesAndroidInjector
  abstract fun contributeMainFragment(): MainFragment
}

If you need to add MainFragmentModule, simply add like this;

@ContributesAndroidInjector(modules = [(MainFragmentModule::class)])

we should specify FragmentModule in our root graph after created fragment module

@Component(modules = [AndroidSupportInjectionModule::class,
  ActivitiesModule::class,
  FragmentModule::class])

now we can inject fragment object. For fragment we can call AndroidSupportInjection.inject(this) in onAttach method before super.

class MainFragment : Fragment() {

  override fun onAttach(context: Context?) {
     AndroidSupportInjection.inject(this)
     super.onAttach(context)

  }

  override
  fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                   savedInstanceState: Bundle?): View? {
     return inflater.inflate(R.layout.main_fragment, container, false)
  }

}

That’s all:) You also can find source code GitHub.


  • 2020-11-22 23:18:59

    Android开发从Dagger2迁移至Kodein的感受

    最近个人在尝试构建 Kotlin版本 的Android MVVM开发框架,在依赖注入框架的选型上,我最终选择了 Kodein 。这是一个非常轻量级的DI框架,相比于配置繁琐的Dagger(繁琐的配置也是导致Dagger学习成本一直居高不下的原因!),它的配置过程更清晰且简单,并且,这个库的源码也是 Kotlin 的。

  • 2020-11-22 23:25:56

    Dagger2源码解析inject过程

    添加inject后,通过编译生成的DaggerMainComponent类来导入,说明编译以后生成了一些类,那到底生成了什么类呢。 Module和Component又是什么,该怎么里理解 在这篇文章后里将一一讨论。

  • 2020-11-22 23:27:28

    dagger学习教程

    dagger android 学习(一):dagger基础使用 dagger android 学习(二):AndroidInjector的使用 dagger android 学习(三):ContributesAndroidInjector的进一步优化 dagger android 学习(四):基于dagger2的mvp架构

  • 2020-11-22 23:31:22

    Dagger2与AndroidInjector详解

    相信使用过Dagger开发Android应用的小伙伴会知道(如果你还不是很了解Daager,可以先看我之前的一篇基本介绍:Dagger2使用攻略),我们会在Activity或Fragment的生命周期方法中执行成员注入。比如这样:

  • 2020-11-23 08:52:59

    asm.js 和 Emscripten 入门教程

    asm.js 就是为了解决这两个问题而设计的:它的变量一律都是静态类型,并且取消垃圾回收机制。除了这两点,它与 JavaScript 并无差异,也就是说,asm.js 是 JavaScript 的一个严格的子集,只能使用后者的一部分语法。

  • 2020-11-23 09:11:07

    爬虫——记一次破解前端加密详细过程

    从最初使用webdriver+selenium爬虫到现在利用http请求解析html,经历过各种各样的问题,webdriver+selenium这种办法虽然万能,而且可以用JS写解析脚本方便调试,

  • 2020-11-24 19:18:43

    nuxtjs打成用于webview的相对路径

    路径为绝对路径,当项目的域名为二级域名的时候,就不能打包为这绝对路径了。 nuxt不同于vue项目,思索了许久,终于找到了配置的地方

  • 2020-11-24 23:22:59

    eruda,移动端网页调试神器

    webapp或者移动端网页需要嵌入到app时候,尤其是在APP内置的webView上加载我们的页面,想要查看手机浏览器信息是非常困难的事,当出现问题的时候,你又不能查看日志,一般会连接本地测试环境,然后在alert来打印日志