2017-02-24 72 views
0

我已经在我的应用程序中设置了dagger2依赖项,并且通过很多示例了解它。我没有找到的是一旦注入它们就可以使用所有依赖的正确方法。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

你是什么意思,“取决于它之前的单身人士的产出”?看起来你的模块结构良好,可以通过在相应的'@ Provide'方法中将每个部分作为输入参数来注入它需要的每个部分。你应该能够注入'OkHttpClient'或者你从MyGameActivity中创建的任何其他依赖。 –

+0

我只是无法在脑海中找到它。我读了更多,概念正在沉入其中。令人沮丧的是有大量文章显示如何设置它,但实际使用示例很难找到。现在我正在用一个体面的例子。谢谢。 –

回答

1

我会尝试一些光棚到这一点,但也有你可以阅读的几种方法。我更喜欢自下而上的方法 - 基本上开始你的对象需要和工作的方式。在这种情况下,我会从MyGameActivity开始。不幸的是,你并没有为此粘贴代码,所以我必须有点创意,但这对于练习的目的来说没关系。

因此,在您的应用程序中,您可能会获得AppComponent,并致电inject为您的MyGameActivity。所以我猜这个活动有一些注射领域。我不确定你是否直接在那里使用OkHttpClient,但我们假设你这样做。例如:

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

我喜欢想这个的方式如下。匕首知道你需要由AppComponent给出的OkHttpClient。所以它会研究如何提供它 - 它可以建立对象本身,因为你用@Inject注释了构造函数吗?它需要更多的依赖性吗?

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

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

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

完成这一切后,您可以创建您的OkHttpClient

我觉得它很容易从这个理解为什么你不能有循环在你的依赖关系图 - 如果它依赖于BB取决于A不能创建一个对象A。所以想象一下,出于某种奇怪的原因,你会达到方法getEndpoint,这取决于该模块的OkHttpClient。这是行不通的。你会在圈子里永远不会结束。

所以,如果我理解你的问题:如何使用整个依赖关系图而不调用每个单身轮流获得所需的输入?

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

但是,据我所知,你做得对。在创建应用程序时,创建组件并缓存它。之后,每次使用方法component()时,总是返回相同的组件,并且范围依赖关系始终相同。

+0

我弄明白了,正在使用它。当我在Spring中进行依赖注入时,很难改变我的思维过程,也很难通过实现来自己设置它。那个匕首只要打一个电话就能做到这一点真的很酷。我给了你一个满意的答案。 –