Dagger2使用整个依赖关系图

时间:2017-02-24 09:31:52

标签: dagger-2

我已经在我的应用程序中设置了dagger2依赖项,因为我理解它并通过许多示例。我没有找到的是在注入后使用所有依赖项的正确方法。

模块中的每个单例取决于之前单例的输出。如何在不调用每个单例的情况下使用整个依赖图来获得所需的输入?

鉴于以下内容:

AppComponent

@Singleton
@Component(modules = {
        DownloaderModule.class
})
public interface AppComponent {
    void inject(MyGameActivity activity);
}

DownloaderModule

@Module
public class DownloaderModule {

    public static final String NETWORK_CACHE = "game_cache";

    private static final int GLOBAL_TIMEOUT = 30; // seconds

    public DownloaderModule(@NonNull String endpoint) {
        this(HttpUrl.parse(endpoint));
    }

    @Provides @NonNull @Singleton
    public HttpUrl getEndpoint() {
        return this.endpoint;
    }

    @Provides @NonNull @Singleton @Named(NETWORK_CACHE)
    public File getCacheDirectory(@NonNull Context context) {
        return context.getDir(NETWORK_CACHE, Context.MODE_PRIVATE);
    }

    @Provides @NonNull @Singleton
    public Cache getNetworkCache(@NonNull @Named(NETWORK_CACHE) File cacheDir) {
        int cacheSize = 20 * 1024 * 1024; // 20 MiB
        return new Cache(cacheDir, cacheSize);
    }

    @Provides @NonNull @Singleton
    public OkHttpClient getHttpClient(@NonNull Cache cache) {
        return new OkHttpClient.Builder()
                .cache(cache)
                .connectTimeout(GLOBAL_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(GLOBAL_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(GLOBAL_TIMEOUT, TimeUnit.SECONDS)
                .build();
    }

MyGameApp

public class MyGameApp extends Application {

    private AppComponent component;

    private static Context context;

    public static MyGameApp get(@NonNull Context context) {
        return (MyGameApp) context.getApplicationContext();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        component = buildComponent();
        MyGameApp.context = getApplicationContext();

      }

    public AppComponent component() {
        return component;
    }

    protected AppComponent buildComponent() {
        return DaggerAppComponent.builder()
                .downloaderModule(new DownloaderModule("https://bogus.com/"))
                .build();
    }

}

1 个答案:

答案 0 :(得分:1)

我会尝试对此有所了解,但有几种方法可以解读这个。我更喜欢自下而上的方法 - 基本上从你的对象需要开始,然后开始工作。在这种情况下,我会从MyGameActivity开始。不幸的是,你没有为此粘贴代码,所以我必须有点创意,但这对练习来说没问题。

因此,在您的应用中,您可能会收到AppComponent并为inject致电MyGameActivity。所以我猜这个活动有一些可注射的字段。我不确定你是否直接在那里使用OkHttpClient,但让我们说你这样做。类似的东西:

public class MyGameActivity extends SomeActivity {
   @Inject
   OkHttpClient okHttpClient;
   // ...
}

我想这样想的方式如下。 Dagger知道你需要OkHttpClient给出的AppComponent。因此,它将研究如何提供它 - 它是否可以构建对象本身,因为您使用@Inject注释了构造函数?它需要更多的依赖吗?

在这种情况下,它将查看提供此客户端的组件的模块。它将达到getHttpClient并意识到它需要一个Cache对象。它将再次查找如何提供此对象 - 构造函数注入,另一个提供程序方法?

它在模块中再次提供,因此它将到达getNetworkCache并再次意识到它需要另一个依赖项。

此行为将继续执行,直到它到达不需要其他依赖项的对象,例如HttpUrl中的getEndpoint

完成所有这些操作后,即可创建OkHttpClient

我认为很容易理解为什么你的依赖图中没有循环 - 如果对象A取决于BB取决于你,则无法创建对象A getEndpoint。因此,想象一下,出于某种奇怪的原因,您将达到方法OkHttpClient,这取决于该模块中的@Singleton。这不行。你会绕圈子永远不会走到尽头。

所以如果我理解你的问题:如何使用整个依赖图而不调用每个单例来获得所需的输入?

不是。它必须调用所有方法才能获得单身人士。至少第一次在相同的组件/范围内提供它们。之后,只要保留组件的相同实例,范围内的依赖项将始终返回相同的实例。匕首会确保这一点。如果由于某种原因破坏组件或重新创建它,那么依赖项将不是相同的实例。更多信息here。事实上,所有范围都是如此。不只是component() s。

然而,据我所知,你做得对。创建应用程序后,您可以创建组件并对其进行缓存。之后,每次使用方法cildren()时,总是返回相同的组件,并且范围的依赖关系始终是相同的。