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.


  • 2019-08-28 09:23:15

    php单例模式

    单例模式,是一种常见的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。

  • 2019-08-28 22:45:02

    彻底搞懂Gradle、Gradle Wrapper与Android Plugin for Gradle的区别和联系

    Gradle是个构建系统,能够简化你的编译、打包、测试过程。熟悉Java的同学,可以把Gradle类比成Maven。Gradle Wrapper的作用是简化Gradle本身的安装、部署。不同版本的项目可能需要不同版本的Gradle,手工部署的话比较麻烦,而且可能产生冲突,所以需要Gradle Wrapper帮你搞定这些事情。Gradle Wrapper是Gradle项目的一部分。

  • 2019-08-30 21:53:51

    OpenSSL实践-Android下的编译和使用

    openssl可以编译成ARM下面的二进制代码(动态库或者静态库),方便APP使用,APP在使用的时候,需要使用JNI来进行调用。

  • 2019-08-31 14:05:00

    JNI Crash:异常定位与捕获处理

    在Android JNI开发中,经常会遇到JNI崩溃的问题,尤其带代码量大,或者嵌入了第三方代码的情况下,很难进行问题定位和处理。本文将介绍两种常见的JNI崩溃处理方法,包括: 每个JNI调用后进行异常检测处理(适用于JNI代码量很小的情况) 捕获系统崩溃的Signal,并进行异常处理(适用于JNI代码量大,难以每句话后面都进行异常检测的情况)