Dagger2 自定义范围:自定义范围(@ActivityScope)实际上如何工作? [英] Dagger2 Custom Scopes : How do custom-scopes (@ActivityScope) actually work?

查看:62
本文介绍了Dagger2 自定义范围:自定义范围(@ActivityScope)实际上如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 GitHub 上阅读 Dagger2 组件范围测试的源代码,我已经看到为名为 @ActivityScope 的活动定义的自定义范围",但我在其他项目中见过它,包括 4-module CleanArchitecture 具有其 @PerActivity 范围.

I am reading the source code for Dagger2 Component Scopes Test on GitHub, and I've seen a "custom scope" defined for activities called @ActivityScope, but I've seen it in other projects including the 4-module CleanArchitecture that has its @PerActivity scope.

但从字面上看,@ActivityScope 注释的代码如下:

But literally, the code for the @ActivityScope annotation is the following:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Scope;

/**
 * Created by joesteele on 2/15/15.
 */
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}

它在模块中神奇地"可用:

And it is "magically" usable in Modules:

@Module
public class ActivityModule {
  @Provides @ActivityScope Picasso providePicasso(ComponentTest app, OkHttpClient client) {
    return new Picasso.Builder(app)
        .downloader(new OkHttpDownloader(client))
        .listener(new Picasso.Listener() {
          @Override public void onImageLoadFailed(Picasso picasso, Uri uri, Exception e) {
            Log.e("Picasso", "Failed to load image: " + uri.toString(), e);
          }
        })
        .build();
  }
}

或者 CleanArchitecture 示例:

@Scope
@Retention(RUNTIME)
public @interface PerActivity {}

@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
  //Exposed to sub-graphs.
  Activity activity();
}

@Module
public class ActivityModule {
  private final Activity activity;

  public ActivityModule(Activity activity) {
    this.activity = activity;
  }

  /**
  * Expose the activity to dependents in the graph.
  */
  @Provides @PerActivity Activity activity() {
    return this.activity;
  }
}

我可以清楚地看到这与 JSR-330 自定义范围有关,但我真的不明白这里到底发生了什么,以便此代码启用给定的模块和/或给定模块提供的内容取决于实际的 Activity 生命周期,并且仅存在单个实例,但前提是该给定 Activity 处于活动状态.

I can clearly see that this has to do with JSR-330 custom scopes, but I really don't understand what exactly is happening here to make it so that this code enables the given module and/or what is provided by a given module to depend on the actual Activity lifecycle, and for there to exist only a single instance but only if that given activity is active.

文档是这样说的:

Scope

Dagger 1 only supported a single scope: @Singleton. 
Dagger 2 allows users to any well-formed scope annotation. 
The Component docs describe the details of 
    how to properly apply scope to a component.

它说要查看组件文档页面,但这给了我 404.我也看到了这个,但是...

It says to look at the Component docs page, but that gives me 404. I also saw this, but...

我可以寻求一些帮助来澄清为什么指定这个自定义范围神奇地使 Activity-level scopes 工作没有问题吗?

May I ask for some help in clarifying why specifying this custom scope magically makes Activity-level scopes work without an issue?

(答案是,子作用域可以从其超作用域接收依赖项,只要组件存在,子作用域就存在.并且您需要在模块上指定作用域,并且需要将组件依赖项指定为子作用域一个超级作用域.)

(The answer is, a subscope can receive dependencies from its superscope, and a subscope exists as long as the component does. And that you need to specify the scopes on your modules, and you need to specify your component dependencies to subscope one superscope.)

推荐答案

值得注意的是,显然 Dagger2 在每个组件的模块中为每个作用域提供者创建了一个实例.

It is worth noting that apparently Dagger2 creates a single instance per scoped provider in a module per component.

因此,为了在模块中获得作用域提供者,您需要为模块的提供者方法指定作用域.

So in order to get a scoped provider in a module, you need to specify the scope for your module's provider method.

@Module
public class YourModule {
    @Provides
    @YourScope //one per component
    public Something something() { return new SomethingImpl(); }

    @Provides //new instance per injection
    public Otherthing otherthing() { return new OtherthingImpl(); }
}

@Component
@YourScope
public interface YourComponent {
    Something something();
    Otherthing otherthing();

    void inject(YourThing yourThing); // only if you want field injection
}

编辑开始:虽然一般来说,你不需要在你的模块中实例化你自己的实现,所以你实际上可以这样做:

EDIT START: though generally, you don't need to instantiate your own implementations inside your modules, so you can actually just do this:

@Module
public abstract class YourModule {
    @Binds
    @YourScope //one per component
    public abstract Something something(SomethingImpl impl);

    @Binds //normally new instance per injection, depends on scope of Impl
    public abstract Otherthing otherthing(OtherthingImpl impl);
}

@Singleton
public class SomethingImpl implements Something {
    @Inject
    SomethingImpl() {
    }
}

// unscoped
public class OtherThingImpl implements OtherThing {
    @Inject
    OtherThingImpl() {
    }
}

@Component
@YourScope
public interface YourComponent {
    Something something();
    Otherthing otherthing();

    void inject(YourThing yourThing); // only if you want field injection
}

编辑结束

之后,参考Kirill的回答;本质上,一个范围"本身仅决定它与另一个范围不同.使用组件依赖项(或子组件)创建一个子作用域.

Afterwards, refer to Kirill's answer; essentially a "scope" by itself only determines that it is a different scope from the other one. Using component dependencies (or subcomponents) creates a subscope.

@Module
public class SubModule {
    @Provides
    @SubScope
    public ThatThing thatThing() { return new ThatThingImpl(); }
}

@Component(dependencies={YourComponent.class}, modules={SubModule.class})
@SubScope
public interface SubComponent extends YourComponent {
    ThatThing thatThing();

    void inject(SubThing subThing); // only if you want field injection
}

一个组件只能依赖一个其他作用域组件.

A component can depend on only one other scoped component.

这篇关于Dagger2 自定义范围:自定义范围(@ActivityScope)实际上如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆