47

私はGitHub でDagger2 Component Scopes Testのソース コードを読んでおり、アクティビティ用に定義された「カスタム スコープ」を見てきましたが、そのスコープを持つ@ActivityScope4 モジュールのCleanArchitecture@PerActivityを含む他のプロジェクトでそれを見てきました。

しかし文字通り、@ActivityScope注釈のコードは次のとおりです。

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 {
}

モジュールで「魔法のように」使用できます。

@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、単一のインスタンスのみが存在しますが、その特定のアクティビティがアクティブな場合のみです。

ドキュメントには次のように書かれています。

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.

Component docs pageを見るように言われていますが、404が表示されます。これも見ましが...

このカスタムスコープを指定すると魔法のように問題なく動作する理由を明確にするために、助けを求めてもActivity-level scopesよろしいですか?

(答えは、サブスコープはそのスーパースコープから依存関係を受け取ることができ、サブスコープはコンポーネントが存在する限り存在するということです。また、モジュールでスコープを指定する必要があり、1 つのスーパースコープをサブスコープするためにコンポーネントの依存関係を指定する必要があります。 )

4

2 に答える 2

40

実は魔法はありません。カスタム スコープの注釈は単なる注釈です。任意の名前を付けることができます。

スコープの最初の機能は、スコープ コンポーネント内で許可されるスコープを Dagger コンパイラに伝える方法です。そのため@ActivityScope、非コンポーネントで依存関係を使用すると@ActivityScope、コンパイル エラーが発生します。

@ActivityScope実際、コンポーネントは多くのスコープ (と など) を宣言でき@UiScope、Dagger はそれらの両方を単一のスコープとして扱います。これはスコープ エイリアシングと呼ばれます。たとえば、マルチモジュール プロジェクトで役立ちます。1 つの Gradle モジュールがその Dagger モジュールで 1 つのスコープを定義し、別の Gradle モジュールが別のスコープを定義している場合、それらの両方を、Dagger コンポーネントを定義する 3 番目の Gradle モジュールで単一のエイリアス スコープとして使用できます。

2 番目の機能は、スコープ コンポーネント内で許可されるインスタンスの数を制限することです。サポートされているスコープにはいくつかのタイプがあります。

スコープなし- アノテーションが宣言されていない場合。Providerスコープ外の依存関係は、キャッシュなしで単純に生成され、コンポーネントで作成されたその依存関係のインスタンスは、新しい注入ごとに新しくなります (コンストラクター内、モジュール プロビジョニング メソッド内、またはフィールドとして)。

@ActivityScopeアノテーションで定義されたカスタムスコープなど@javax.inject.Scope- そのスコープで宣言された依存関係は、二重チェックロックが生成されたキャッシングProviderを持ち、同じスコープで宣言されたコンポーネント内で単一のインスタンスのみが作成され、その作成はスレッドセーフになります。コンポーネント自体のすべてのインスタンスに対して、その依存関係の新しいインスタンスが作成されることに注意してください。

再利用可能なスコープ-@dagger.Reusable注釈で宣言 - そのスコープで宣言された依存関係は、共通の親コンポーネントを介して異なるコンポーネント間で共有される場合がありProvider、単一チェック ロックが生成されたキャッシングが行われます。依存関係が必ずしも単一のインスタンスを持つ必要はないが、単一のコンポーネントまたはコンポーネント間でパフォーマンスを向上させる (割り当てを減らす) ために共有できる場合に役立ちます。

スコープの仕組みの詳細については、ユーザー ガイドと Dagger の生成コードを参照してください。

実際のスコープを定義する方法は、あなたの特権です。スコープ コンポーネントの作成時と破棄時のライブサイクルを定義します。これがスコープです。たとえば@ActivityScope、アクティビティのライブサイクルに関連付けられており、次のように定義されています。

private ActivityComponent component;

@Override
protected void onCreate(Bundle savedInstanceState) {
    component = DaggerActivityComponent.builder().build();
    component.inject(this);
}

@Override
protected void onDestroy() {
    component = null;
    super.onDestroy();
}

だから魔法はありません。スコープを使用するセマンティクスによってスコープを定義します。この回答これらの例も役立つ場合があります。

EDIT 14.10.2018以前の回答のあいまいさを排除するために、スコープ関数と型を拡張しました。

于 2015-04-29T12:27:42.797 に答える