如何在不强制消耗应用程序使用 Dagger 的情况下构建基于 Dagger 的 Android 库?

2022-09-01 17:38:30

我正在开发一个Android库,它基本上是我编写的一些REST服务的客户端。我有几个存储类,网络队列,解析器等,并且像许多这样的类一样,它们依赖于或依赖于从 构造的类似的东西。这些对象都隐藏在一个 façade 类后面,因此我的库的使用者看不到它们或直接与它们交互。ContextSharedPreferencesContext

为了我自己的理智,我想使用Dagger 2进行依赖注入,以便在我的库中内部管理这些类的实例。但是,我不想强迫使用我的库的应用程序自己使用Dagger;仅仅因为我选择使用Dagger并不意味着我的用户应该这样做。

我看过的所有教程似乎都希望我正在构建一个应用程序,而不仅仅是一个库。其中许多教程告诉我,我应该让我的类继承自 .但是,就我而言,我的库中根本没有(或任何类),我不希望我的用户必须使用Dagger的基类。ApplicationDaggerApplicationApplicationActivityService

那么,我如何使用匕首而不将其“泄漏”出我的库呢?我在这里找到了部分答案,但我不确定如何调整作者的“包装器”模式来处理我对的依赖性。我可以只将上下文传递到包装器的方法中,还是Dagger能够以其他方式获取上下文引用?ContextgetComponent()


答案 1

几乎就像一个应用程序(当涉及到Dagger时)。是的,你没有对象,但你真的不需要一个。application

作为你的图书馆的消费者,我希望它易于使用,所以我根本不想知道匕首是什么(或者你是否在内部使用它)。

例如,让您的用户在首次调用您的库时通过 a。有一个(我认为你的示例称之为包装器),它具有对接口的静态引用。ContextDaggerInjectorComponent

示例(因此,只是一个通用示例):

public class DaggerInjector {

    private static YourComponent component;

    private DaggerInjector() {
        super();
    }

    public static YourComponent getComponent() {
        return component;
    }

    public static YourComponent buildComponent(Context context) {
        component = DaggerYourComponent
                .builder()
                .yourModule(new YourModule(context))
                .build();
        return component;
    }
}

您的“模块”可以如下所示:

@Module
public class YourModule {

    private Context context;

    public YourModule(Context context) {
        this.context = context;
    }

    @Provides
    @Singleton
    final Context providesContext() {
        return context;
    }
}

要使用它:

让用户调用方法(或者,如果组件为 null,则首次自行调用该方法):

DaggerInjector.buildComponent(context);

这将确保初始化 Dagger 组件并生成代码。要知道调用是一项昂贵的任务(Dagger 必须做很多事情!),所以只做一次(除非你需要使用仅在运行时已知的不同值重新初始化库)。buildComponent

一些图书馆只是在每次通话中都要求上下文,因此这并非不可能;然后,您可以在第一次调用时初始化 dagger(通过检查 getComponent() 在注入器中是否为空)。

在你的不再为空之后,你现在可以添加和适当的“可注射”的东西......DaggerInjector.getComponent()@Inject

例如:在你可以有:YourModule

@Provides
SomeObject providesSomeObject() {
    return new SomeObject();
}

// THIS “Context” here is automatically injected by Dagger thanks to the above.
@Provides
@Singleton
SomeOtherObject providesSomeOtherObject(Context context) {
    return new SomeOtherObject(context); //assume this one needs it
}

在任何“可注入”对象(即,在您的组件中具有方法的对象...)中,您可以执行以下操作:inject

public class AnObjectThatWantsToInjectStuff {

    @Inject
    SomeObject someObject;
    @Inject 
    SomeOtherObject someOtherObject;

    public AnObjectThatWantsToInjectStuff() {
          super();
          DaggerInjector.getComponent().inject(this);

          // you can now use someObject and someOtherObject
    }
}

要使上述内容正常工作,您需要在(这是一个接口)代码中,如下所示:YourComponent

void inject(AnObjectThatWantsToInjectStuff object);

(否则调用将在编译时失败)DaggerInjector.getComponent().inject(this)

注意我从来没有传递过上下文,匕首已经知道如何获得它。YourInjectableContext

小心泄漏。我建议您存储而不是对所有/大多数情况都只进行普通存储(除非您明确需要活动上下文来扩展布局/主题目的,否则使用应用程序提供的应用程序上下文就是您所需要的)。context.getApplicationContext()Context


答案 2

推荐