前言
稍微复杂一点的安卓应用基本上都采用了Dagger。但是,很多工程师在学习Dagger的过程中,都抱怨学习曲线很陡峭,上手不容易。究其原因,主要是因为Dagger在编译阶段自动生成了很多代码。而通常情况下,工程师是不会阅读或者理解这些代码的。这就导致了许多安卓工程师只会机械地照搬Dagger的示例教程,而不能从原理上深入理解Dagger的实现。因此,在很多项目中,Dagger无法发挥出它的全部优势,有时甚至会被用错。
为了解决上述问题,我们尝试对Dagger进行源码级别的剖析,以此加深对Dagger的理解。
项目概览
本文将基于一个叫DaggerBasic的项目进行源码分析。这个项目包含了MainActivity、MainViewModel、MainComponent和MainModule。各个类之间的关系图如下所示。
经过编译之后,Dagger会自动生成如下类文件:
- DaggerMainComponent:MainComponent的实现类,提供MainActivity所需的依赖对象。
- MainViewModel_Factory:MainViewModel的工厂类,负责创建MainViewModel。
- MainActivity_MembersInjector:负责向MainActivity注入依赖对象的类。
- MainModule_ProvideSharedPreferencesFactory:负责提供SharedPreferences的工厂类。
接下来我们就逐个分析一下上述生成的类及其功能。
DaggerMainComponent
MainComponent是MainActivity对应的依赖关系图,所有MainActivity依赖的对象,都可以通过MainComponent获得。为了让Dagger能够提供这些对象,开发者需要创建一个接口,并使用 @Component为其添加注释。而Dagger则会自动为我们生成这个接口的实现。
MainComponent的代码如下所示。
@Component(modules = [MainModule::class])
interface MainComponent {
fun inject(activity: MainActivity)
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): MainComponent
}
}
而DaggerMainComponent则是MainComponent的实现类,代码如下所示。
public final class DaggerMainComponent implements MainComponent {
private final Context context;
private final MainModule mainModule;
private DaggerMainComponent(MainModule mainModuleParam, Context contextParam) {
this.context = contextParam;
this.mainModule = mainModuleParam;
}
public static MainComponent.Factory factory() {
return new Factory();
}
private SharedPreferences getSharedPreferences() {
return MainModule_ProvideSharedPreferencesFactory.provideSharedPreferences(mainModule, context);
}
private MainViewModel getMainViewModel() {
return new MainViewModel(getSharedPreferences());
}
@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);
}
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectMainViewModel(instance, getMainViewModel());
return instance;
}
private static final class Factory implements MainComponent.Factory {
@Override
public MainComponent create(Context context) {
Preconditions.checkNotNull(context);
return new DaggerMainComponent(new MainModule(), context);
}
}
}
可以看到,DaggerMainComponent最重要的职责就是提供MainViewModel和SharedPreferences两个依赖对象。对于MainViewModel,DaggerMainComponent总是创建新的对象实例(我们会在讲解Scope的时候详细描述如何对这个行为进行优化)。对于SharedPreferences,DaggerMainComponent则是利用MainModule_ProvideSharedPreferencesFactory来创建SharedPreferences对象实例。
同时,DaggerMainComponent实现了inject方法。该方法接收一个MainActivity实例,并将MainActivity需要的依赖对象赋值给它,从而完成依赖注入。
最后,DaggerMainComponent还提供了MainComponent.Factory的实现,它被用来创建DaggerMainComponent的对象实例。
MainViewModel_Factory
MainViewModel_Factory是MainViewModel的工厂类,负责创建MainViewModel的实例。在这个例子中,由于我们没有为MainViewModel定义Scope,因此DaggerMainComponent总是直接调用MainViewModel的构造方法创建新的MainViewModel实例。我们将在后续的例子中展示MainViewModel_Factory的功能。
MainViewModel的代码如下所示。
class MainViewModel @Inject constructor(sharedPreferences: SharedPreferences)
MainViewModel_Factory的源代码如下所示。
public final class MainViewModel_Factory implements Factory<MainViewModel> {
private final Provider<SharedPreferences> sharedPreferencesProvider;
public MainViewModel_Factory(Provider<SharedPreferences> sharedPreferencesProvider) {
this.sharedPreferencesProvider = sharedPreferencesProvider;
}
@Override
public MainViewModel get() {
return new MainViewModel(sharedPreferencesProvider.get());
}
public static MainViewModel_Factory create(
Provider<SharedPreferences> sharedPreferencesProvider) {
return new MainViewModel_Factory(sharedPreferencesProvider);
}
public static MainViewModel newInstance(SharedPreferences sharedPreferences) {
return new MainViewModel(sharedPreferences);
}
}
MainActivity_MembersInjector
MainActivity_MembersInjector接收MainActivity实例并负责向它注入依赖对象。Dagger会为每一个需要注入依赖对象的Activity生成一个MembersInjector。MainActivity_MembersInjector在DaggerMainComponent的injectMainActivity被调用。
MainActivity的代码如下所示。
class MainActivity : AppCompatActivity() {
@Inject
lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
DaggerMainComponent.factory().create(applicationContext).inject(this)
super.onCreate(savedInstanceState)
}
}
MainActivity_MembersInjector的源代码如下。
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<MainViewModel> mainViewModelProvider;
public MainActivity_MembersInjector(Provider<MainViewModel> mainViewModelProvider) {
this.mainViewModelProvider = mainViewModelProvider;
}
public static MembersInjector<MainActivity> create(
Provider<MainViewModel> mainViewModelProvider) {
return new MainActivity_MembersInjector(mainViewModelProvider);
}
@Override
public void injectMembers(MainActivity instance) {
injectMainViewModel(instance, mainViewModelProvider.get());
}
public static void injectMainViewModel(MainActivity instance, MainViewModel mainViewModel) {
instance.mainViewModel = mainViewModel;
}
}
可以看到,在injectMainViewModel方法中,MainActivity_MembersInjector将MainViewModel的实例赋给了MainActivity对于的成员变量,从而完成了依赖注入。
MainModule_ProvideSharedPreferencesFactory
MainModule的代码如下所示。
@Module
class MainModule {
@Provides
fun provideSharedPreferences(appContext: Context): SharedPreferences {
return appContext.getSharedPreferences("SharedPreferences", MODE_PRIVATE)
}
}
针对Module中每一个被标记为@Provides的方法,Dagger会生成一个工厂类,用来提供对应的依赖对象。在这个例子中,Dagger为provideSharedPreferences生成了MainModule_ProvideSharedPreferencesFactory类,它可以提供SharedPreferences的实例,其源代码如下:
public final class MainModule_ProvideSharedPreferencesFactory
implements Factory<SharedPreferences> {
private final MainModule module;
private final Provider<Context> appContextProvider;
public MainModule_ProvideSharedPreferencesFactory(
MainModule module, Provider<Context> appContextProvider) {
this.module = module;
this.appContextProvider = appContextProvider;
}
@Override
public SharedPreferences get() {
return provideSharedPreferences(module, appContextProvider.get());
}
public static MainModule_ProvideSharedPreferencesFactory create(
MainModule module, Provider<Context> appContextProvider) {
return new MainModule_ProvideSharedPreferencesFactory(module, appContextProvider);
}
public static SharedPreferences provideSharedPreferences(
MainModule instance, Context appContext) {
return Preconditions.checkNotNull(
instance.provideSharedPreferences(appContext),
"Cannot return null from a non-@Nullable @Provides method");
}
}
总结
通过上述分析,我们可以通过下面这张图来展示Dagger生成的类及其对应关系。
左边的类是开发者定义的接口或者类,右边的类是Dagger生成的类。二者的桥梁就是Dagger注解。通过上述分析,我们就很好理解为什么在MainActivity的onCreate方法中,我们要插入如下代码了。
DaggerMainComponent.factory().create(applicationContext).inject(this)
其实这行代码就是创建DaggerMainComponent,生成MainActivity需要的依赖对象图,然后将依赖对象注入到MainActivity中。
至此,我们从源码级别对Dagger进行了基本的分析,展示了Component和Module是如何工作的。读者可以发现,其实Dagger并没有那么神秘,它只不过按照最优的方式为我们生成了一些模板方法,节约了开发者的时间而已。在后续的文章中,我们还将从源码级别分析其他Dagger的高级特性,欢迎关注。