使用 Dagger 2 在库模块中注入应用程序上下文

Injecting application context in library module with Dagger 2

我正在构建一个具有以下功能的应用程序:ContentProvider、SyncAdapter、作业服务和相关的持久性逻辑。在这些之上还有 UI 的活动。我试图将所有上述功能放在一个单独的库模块中,因为理论上它们的逻辑是独立的并且可以被任何应用程序重用。

Dagger2 来了。我的库的依赖关系图的第一个节点(主组件)确实需要提供上下文,并且这个上下文必须从应用程序中注入,因为库范围具有与应用程序相同的生命周期。为了自包含,显然,我的库不应该直接使用我的应用程序 class.

这些是我想到的可能性:

正确的做法是什么?

Dagger 2 for Android 来救援。它提供了 AndroidInjector 的概念,这是一个 Component 可以用于以静态方式注入实例,而无需知道依赖提供者。此外,使用开箱即用的 Dagger- 前缀 类 ,注入的依赖项看起来像是无处不在。太棒了。

您所要做的就是在库中声明一个 top-level Module,它安装在应用程序 Component 中。 Module 将提供库所需的所有依赖项和 SubComponents,它将自动继承您在依赖关系图中播种的 @AppContext Context,随时可以注入库中的任何位置,以及您通过主应用程序 Component.

提供的每个依赖项

这是一个简短的例子(用 Kotlin 编写):

@Component(modules = [
    AndroidSupportInjectionModule::class,
    AppModule::class,
    LibraryModule::class //plug-in the library to the dependency graph
])
@Singleton
interface AppComponent : AndroidInjector<App> {

    @Component.Builder
    abstract class Builder : AndroidInjector.Builder<App>() {

        @BindsInstance
        abstract fun appContext(@AppContext context: Context)

        override fun seedInstance(instance: App) {
            appContext(instance)
        }
    }
}

编辑:扩展示例

Application 子类的示例:

// DaggerApplication provides out-of-the-box support to all the AndroidInjectors.
// See the class' code to understand the magic.
public class App extends DaggerApplication {

@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
    // We only provide its own Injector, the Application Injector,
    // that is the previous AppComponent
    return DaggerAppComponent.builder().create(this);
}

在您的 Android 图书馆中:

@Module
public abstract class LibraryModule {

    @ContributesAndroidInjector
    public abstract LibraryActivity contributeLibraryActivityInjector();

}

public class LibraryActivity extends DaggerAppCompatActivity {

    @Inject
    @AppContext
    Context appContext;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceSate);
        // here you automagically have your injected application context!
        ExternalSingleton.getInstance(appContext)
    }
}