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

时间:2017-07-10 22:37:32

标签: java android dagger-2 dagger

我正在开发一个Android库,它基本上是我写过的一些REST服务的客户端。我有几个存储类,网络队列,解析器等,并且像许多这样的类一样,它们依赖于ContextSharedPreferences构建的Context之类的依赖项。这些对象都隐藏在外观类后面,因此我的图书馆的消费者不会看到它们或直接与它们互动。

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

我所见过的所有教程似乎都期望我构建一个应用程序,而不仅仅是一个库。其中许多教程告诉我,我应该让Application类继承自DaggerApplication。但就我而言,我的图书馆根本没有Application(或任何ActivityService课程),我也不想要我的用户必须使用Dagger的基类。

那么如何在没有"泄漏的情况下使用Dagger"它出了我的图书馆?我找到了部分答案here,但我不确定如何适应作者的#34;包装"模式来处理我对Context的依赖。我可以将上下文传递给包装器的getComponent()方法,还是Dagger能够以其他方式获取上下文引用?

1 个答案:

答案 0 :(得分:14)

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

作为图书馆的消费者,我希望它的使用简单,所以我不想知道匕首是什么(或者如果你在内部使用它)。

让您的用户在第一次呼叫您的图书馆时传递Context(例如)。请DaggerInjector(我认为您的示例称之为包装器)具有对Component接口的静态引用。

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

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组件并生成代码。理解调用buildComponent是一项昂贵的任务(Dagger必须做很多事情!)所以只做一次(除非你需要在运行时使用不同的值重新初始化库)。

有些图书馆只是在每个电话中都要求一个上下文,所以这不是不可能的;然后,你可以在第一次调用时初始化dagger(通过检查注入器中的getComponent()是否为null)。

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,Dagger已经知道如何获取它。

小心泄漏。对于所有/大多数情况,我建议你存储context.getApplicationContext()而不是普通的Context(除非你明确需要一个Activity上下文来膨胀布局/主题目的,消费应用程序提供的应用程序上下文就是你所有的需要)。