【Android】Dagger2 通过 AndroidInjector 简化模版代码
前面我们已经详细讲解过,如何通过 Component 和 Module 向 Activity 注入对象
这是基本的使用方法,它的缺点是当 Activity 特别多时,就需要非常多的 Component 和 Module 类
现在我们来讲解,如何通过 AndroidInjector 向基类进行统一注入
AndroidInjector 使用方法
定义 DatabaseObject,可用依赖于不同对象,在不同 Activity 中有不同作用
public class DatabaseObject {HomeActivity homeActivity;SplashActivity splashActivity;public DatabaseObject() {}public DatabaseObject(HomeActivity homeActivity) {this.homeActivity = homeActivity;}public DatabaseObject(SplashActivity splashActivity) {this.splashActivity = splashActivity;}
}
定义 ApplicationComponent
@Component(modules = {AndroidInjectionModule.class,BaseActivityModule.class
})
public interface ApplicationComponent {void inject(APP app);
}
定义 ApplicationComponent 的子组件
注意,这里的 Module 不同于常规的 Module,它并不用来提供对象,而是用来提供子组件的
Dagger 会根据每个@Contributes
方法创建一个对应的SubComponent
@Module
public abstract class BaseActivityModule {@ContributesAndroidInjector(modules = HomeActivityModule.class)abstract HomeActivity contributesHomeActivity();@ContributesAndroidInjector(modules = SplashActivityModule.class)abstract SplashActivity contributesSplashActivity();
}
创建提供 Object 的 Module
DatabaseObject 依赖于 Activity,每个 Activity 的 Object 都是一个单独的实例,这种情景可用通过静态方法去创建
@Module
public class HomeActivityModule {@Providesstatic DatabaseObject provideDatabaseObject(HomeActivity homeActivity) {return new DatabaseObject(homeActivity);}
}
@Module
public class SplashActivityModule {@Providesstatic DatabaseObject provideDatabaseObject(SplashActivity splashActivity) {return new DatabaseObject(splashActivity);}
}
通过 ApplicationComponent 向 Application 注入 AndroidInjector
AndroidInjector 能够访问所有的 Component 和 Module,这样它就能自动帮助我们向 Activity 注入对象了
public class APP extends Application {public static APP application;ApplicationComponent applicationComponent;@InjectDispatchingAndroidInjector<Object> androidInjector;@Overridepublic void onCreate() {super.onCreate();application = this;applicationComponent = DaggerApplicationComponent.create();applicationComponent.inject(this);}public static ApplicationComponent applicationComponent() {return application.applicationComponent;}public static AndroidInjector<Object> androidInjector() {return application.androidInjector;}
}
通过 AndroidInjector 向 Activity 统一注入对象
AndroidInjector 会根据之类 Activity 的真实类名,来找到对应的 Component 和 Module,然后帮我们自动注入对象
public class BaseActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);AndroidInjector androidInjector = APP.application.androidInjector();androidInjector.inject(this);}
}
效果测试
@SuppressWarnings("all")
public class HomeActivity extends BaseActivity {ActivityHomeBinding binding;@InjectDatabaseObject databaseObject;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityHomeBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());test();}@Functionprotected void test() {System.err.println(databaseObject.hashCode());}@Overridepublic void onBackPressed() {finish();startActivity(new Intent(this, HomeActivity.class));}
}
通过打印结果可以看到,对象确实注入成功了
只要我们在 BaseActivity 写一行注入代码,就可用为所有 Activity 自动注入对象
Dagger 原理分析
上面已经给出使用方法,下面我们再逐步讲解代码作用,以及 Dagger 是如何生成代码的
这里我没有给出完整的源码,而是将代码的核心流程概述出来
因为 Dagger 的代码量特别大,但是流程本身其实很简单,给出大量模版代码反而会影响大家去理解核心流程
通过 BaseActivityModule 简化代码
-
ApplicationComponent
依赖BaseActivityModule
-
BaseActivityModule中
的每个@Contribute
方法,都会对应生成一个SubActivityComponent
类 -
BaseActivityModule
中的每个@Contribute
方法,都会对应生成一个SubActivityComponentFactory
类 -
BaseActivityModule
和AndroidInjector
之所以能简化代码,是因为 Dagger 根据@Contribute
方法自动帮我们生成了SubActivityComponent
-
实际上,这里的
BaseActivityModule
只是用来标记要生成哪些SubActivityComponent
的,在源码中根本就没有用到它 -
如果我们需要向
BaseActivity
中统一注入其它对象,可以自己单独再创建一个 Module
AndroidInjector 和 ApplicationComponent 之间的关系
整体的思路我们已经清楚了,是 Dagger 帮我们省略了许多的模版代码工作,现在我们开始理一下细节上是如何实现的
我们是统一通过 AndroidInjector 去注入的,实现的关键在于 AndroidInjector 如何提供 Activity
-
所有工作都是从
ApplicationComponent
开始的,而且它是单例的,所以任何对象都能拿到它的引用 -
ApplicationComponent
依赖AndroidInjectionModule
,这个 Dagger 内置 Module 可以帮我们注入AndroidInjector
对象 -
ApplicationComponent
在向 Application 注入AndroidInjector
时,同时会将自己所有的SubComponentFactoryProvider
全部传给AndroidInjector
-
因此
AndroidInjector
实际是通过ApplicationComponent::SubComponentFactoryProvider
来提供 Activity 的 -
SubComponentFactoryProvider
做的工作很简单,直接 new 一个SubComponentFactory
-
AndroidInjector
向 Activity 注入对象时,实际是根据Activity::className
找到对应的Provider
,通过Provider
创建Factory
,通过Factory
创建SubComponent
,将当前 Activity 实例传给SubComponent
,剩下的注入工作交给SubComponent
就好了 -
以上是通过
ApplicationComponent
拿到SubComponent
的过程,SubComponent
拿到Object
的流程大体相似,主要是通过Provider
+Factory
SubComponent 如何注入 Object
-
AndroidInjector
定义了一个 inject 方法,负责向AndroidTarget
注入对象 -
AndroidInjector.Factory
定义了一个 create 方法,负责根据AndroidTarget
创建AndroidInjector
-
AndroidInjector
分为两种,一种是专门为绑定的AndroidTarget
注入对象,一种是DispatchingAndroidInjector
,自身不负责注入对象,而是将注入工作分发给SubAndroidInjector
去处理 -
ApplicationComponent
内部包含了多个SubComponent.Factory
,它们继承自AndroidInjector.Factory
接口,用于创建SubComponent
-
SubComponent
实现了AndroidInjector
接口,用于向绑定的 Activity 注入对象 -
SubComponent
就是SubAndroidInjector
,所以上一节中,Application::AndroidInjector
的实际是在管理SubAndroidInjector
-
SubComponent
内部持有了Module
和Activity
,然后将这两个对象交给ObjectFactory
-
ObjectFactory
会生成一个静态方法,该方法接受Module
和Activity
两个参数,然后调用Module::staticProvide
方法来创建 Object