web-dev-qa-db-ja.com

Dagger v2:2つの異なるスコープを1つのオブジェクトに挿入します

ModuleAをアプリケーション全体のシングルトンプロバイダーとしてセットアップし、ModuleBをユーザー関連のオブジェクトプロバイダーとしてセットアップしました

私のユーザー表示フラグメントは、システム全体のバスを使用して他のユーザーにメッセージを送信し、ユーザー関連のオブジェクトを使用して表示します。

問題は、異なるscropeクラスを1つのオブジェクトに挿入できません。 component.getXメソッドを使用すると正常に機能しますが、注入することをお勧めします。エラーメッセージ:@ UserScopeはスコープが異なるバインディングを参照できない可能性があります:@Provides @Singleton Bus ModuleA.provideBus()

@Module
public class ModuleA {
  @Provides @Singleton Bus provideBus() {...}
}

ユーザー関連の情報プロバイダーとしてのモジュールB

@Module
public class ModuleB{
  private final User user;
  public ModuleB(User user) {...}
  @Provides @UserScope User provideUser() {}
  @Provides @UserScope UserManager provideUserManager() {}
}

次のようなコンポーネントのセットアップ:

@Component (modules={ModuleA.class})
@Singleton
public interface ComponentA {
  Bus getBus();
  void inject(ClassA target);
}

@Component(modules={ModuleB.class})
@UserScope
public interface ComponentB {
  User getUser();
  UserManager getUserManager();
  void inject(ClassA target);
}


class UserFragment exrtends Fragment {
   @Inject Bus bus;
   @Inject UserManager userManager;
   public void onCreate() {
      getComponentA().inject(this);
      getComponentB().inject(this);
   }
}
10
Xiaofeng

この構成を試してください、それは私のために働きます。 Dagger2に関する優れたドキュメントが本当に不足しているため、GitHubなどでDagger2のようなキーワードで見つけることができるコードのオープンソースの例をいくつか調べました。

アプリケーションレベルのコンポーネント

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    // exported for child-components
    Bus eventBus();
}

アプリケーションレベルのモジュール

@Module
public class AppModule {
    @Provides @Singleton
    Bus provideBus() {
        return BusProvider.getInstance();
    }
}

アクティビティレベルコンポーネント

@ActivityScope
@Component(dependencies=AppComponent.class, modules=MainActivityModule.class)
public interface MainActivityComponent {
    void inject( MainActivity mainActivity );
}

アクティビティレベルモジュール

@Module
public class MainActivityModule {
    private final MainActivity mActivity;

    public MainActivityModule( MainActivity activity ) {
        mActivity = activity;
    }

    @Provides
    MainActivityTitleController provideTitleController() {
        return new MainActivityTitleController( mActivity );
    }
}

Androidアプリケーションクラス

public class MyApplication extends Application {
    private AppComponent mAppComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        // Dagger2
        mAppComponent = Dagger_AppComponent.builder()
            .appModule( new AppModule( this ))
            .build();
    }

    public AppComponent getComponent() {
        return mAppComponent;
    }

    public static AppComponent getComponent( Context context ) {
        return ((MyApplication)context.getApplicationContext()).getComponent();
    }
}

そして最後にアクティビティ

public class MainActivity extends ActionBarActivity {

    // Injectable fields
    @Inject Bus mEventBus;
    @Inject MainActivityTitleController mTitleController;

    private MainActivityComponent mComponent;

    @Override
    protected void onCreate( Bundle savedInstanceState ) {
        // Dagger2
        mComponent = Dagger_MainActivityComponent.builder()
            .appComponent( ((MyApplication)getApplication()).getComponent() )
            .mainActivityModule( new MainActivityModule( this ) )
            .build();
        mComponent.inject( this );
    }
}
23
Vlad Kuts

提供したコードスニペットの主な問題は、取得したエラーをシングルトンに正しく提供するために、ModuleBModuleAに依存している必要があることだと思います。つまりこれはうまくいくはずです:

@Component(modules={ModuleB.class}, dependencies = ComponentA.class)
@UserScope
public interface ComponentB {
    User getUser();
    UserManager getUserManager();
    void inject(MainActivity target);
}

私はあなたのクラスを再作成し、空白を埋めるためにいくつかの仮定をしました、そしてそれはうまくいくようです。完全に機能するコードを見ることができます ここではGitHub 。私のコードの唯一の違いは、あなたがClassA/UserFragmentと呼んだものです。私はMainActivityと呼んだだけですが、それ以外は構造は同じです。

9
G. Lombard