Dagger 2.11 ContributesAndroidInjector Singleton依赖注入失败

lim*_*nal 3 dagger dagger-2

我正在从Dagger 2.11中探索新的dagger.android.我希望不必创建自定义范围注释@PerActivity.到目前为止,我能够做到以下几点:

1)定义应用程序范围单例并将它们注入活动.

2)定义活动范围非单例依赖关系,并使用它们将它们注入到它们的活动中 @ContributesAndroidInjector

我无法弄清楚的是如何使用它的应用程序范围Singleton和Activity范围非单例.

在下面的示例中,我想要我的活动范围MyActivityDependencyAMyActivityDependencyB可以访问SingletonMyActivityService

以下设置导致:

错误:(24,3)错误:com.example.di.BuildersModule_BindMyActivity.MyActivitySubcomponent(unscoped)可能不引用作用域绑定:@Singleton @Provides com.example.MyActivityService com.example.MyActivitySingletonsModule.provideMyActivityService()

这是我的设置.注意,我定义了单独的MyActivitySingletonsModule, MyActivityModule因为我不能在同一个Module文件中混合使用Singleton和非Singleton依赖项.

@Module
public abstract class BuildersModule {
    @ContributesAndroidInjector(modules = {MyActivitySingletonsModule.class, MyActivityModule.class})
    abstract MyActivity bindMyActivity();
    }
}
Run Code Online (Sandbox Code Playgroud)

@Module
public abstract class MyActivityModule {
    @Provides
    MyActivityDependencyA provideMyActivityDependencyA(MyActivityService myActivityService){
       return new MyActivityDependencyA(myActivityService);
    }
    @Provides
    MyActivityDependencyB provideMyActivityDependencyB(MyActivityService myActivityService) {
        return new MyActivityDependencyB(myActivityService);
    }
}
Run Code Online (Sandbox Code Playgroud)

@Module
public abstract class MyActivitySingletonsModule {
    @Singleton
    @Provides
    MyActivityService provideMyActivityService() {
        return new MyActivityService();
    }
}
Run Code Online (Sandbox Code Playgroud)

@Singleton
 @Component(modules = {
    AndroidSupportInjectionModule.class,
    AppModule.class,
    BuildersModule.class})

public interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(App application);
        AppComponent build();
    }
    void inject(App app);
}
Run Code Online (Sandbox Code Playgroud)

如果不定义自定义范围注释,甚至可以做我想做的事情吗?

提前致谢!

Van*_*ado 10

为什么要避免自定义范围?Dagger 2.10+中引入的新dagger.android依赖注入框架仍然需要自定义范围.

"我的理解是@ContributesAndroidInjector不再需要自定义注释,我能够通过使用活动范围中定义的非单例来证明它,而没有任何问题."

@ContributesAndroidInjector(在v2.11中提供)不会消除对自定义作用域的需要.它仅仅取代了声明@Subcomponent不使用的类@Subcomponent.Builder在运行时注入组件所需的依赖项的需要.请查看官方dagger.android用户指南@ContributesAndroidInjector中的以下代码段;

"专业提示:如果您的子组件及其构建器没有其他方法或超类型,而不是步骤2中提到的方法或超类型,您可以使用@ContributesAndroidInjector为您生成它们.而不是步骤2和3,添加一个抽象模块方法,返回您的活动,使用@ContributesAndroidInjector对其进行注释,并指定要安装到子组件中的模块.如果子组件需要范围,也可以将范围注释应用于该方法."

@ActivityScope
@ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ })
abstract YourActivity contributeYourActivityInjector();
Run Code Online (Sandbox Code Playgroud)

这里的关键是"如果子组件需要范围,也可以将范围注释应用于方法."

看看下面的代码如何使用的概述@Singleton,@PerActivity,@PerFragment,并@PerChildFragment与新的定制范围dagger.android注入框架.

// Could also extend DaggerApplication instead of implementing HasActivityInjector
// App.java
public class App extends Application implements HasActivityInjector {

    @Inject
    AppDependency appDependency;

    @Inject
    DispatchingAndroidInjector<Activity> activityInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        DaggerAppComponent.create().inject(this);
    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return activityInjector;
    }
}

// AppModule.java
@Module(includes = AndroidInjectionModule.class)
abstract class AppModule {
    @PerActivity
    @ContributesAndroidInjector(modules = MainActivityModule.class)
    abstract MainActivity mainActivityInjector();
}

// AppComponent.java
@Singleton
@Component(modules = AppModule.class)
interface AppComponent {
    void inject(App app);
}

// Could also extend DaggerActivity instead of implementing HasFragmentInjector
// MainActivity.java
public final class MainActivity extends Activity implements HasFragmentInjector {

    @Inject
    AppDependency appDependency; // same object from App

    @Inject
    ActivityDependency activityDependency;

    @Inject
    DispatchingAndroidInjector<Fragment> fragmentInjector;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);

        if (savedInstanceState == null) {
            addFragment(R.id.fragment_container, new MainFragment());
        }
    }

    @Override
    public final AndroidInjector<Fragment> fragmentInjector() {
        return fragmentInjector;
    }
}

// MainActivityModule.java
@Module
public abstract class MainActivityModule {
    @PerFragment
    @ContributesAndroidInjector(modules = MainFragmentModule.class)
    abstract MainFragment mainFragmentInjector();
}

// Could also extend DaggerFragment instead of implementing HasFragmentInjector
// MainFragment.java
public final class MainFragment extends Fragment implements HasFragmentInjector {

    @Inject
    AppDependency appDependency; // same object from App

    @Inject
    ActivityDependency activityDependency; // same object from MainActivity

    @Inject
    FragmentDependency fragmentDepency; 

    @Inject
    DispatchingAndroidInjector<Fragment> childFragmentInjector;

    @SuppressWarnings("deprecation")
    @Override
    public void onAttach(Activity activity) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            // Perform injection here before M, L (API 22) and below because onAttach(Context)
            // is not yet available at L.
            AndroidInjection.inject(this);
        }
        super.onAttach(activity);
    }

    @Override
    public void onAttach(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // Perform injection here for M (API 23) due to deprecation of onAttach(Activity).
            AndroidInjection.inject(this);
        }
        super.onAttach(context);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.main_fragment, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        if (savedInstanceState == null) {
            addChildFragment(R.id.child_fragment_container, new MainChildFragment());
        }
    }

    @Override
    public final AndroidInjector<Fragment> fragmentInjector() {
        return childFragmentInjector;
    }
}

// MainFragmentModule.java
@Module
public abstract class MainFragmentModule {
    @PerChildFragment
    @ContributesAndroidInjector(modules = MainChildFragmentModule.class)
    abstract MainChildFragment mainChildFragmentInjector();
}

// MainChildFragment.java
public final class MainChildFragment extends Fragment {

    @Inject
    AppDependency appDependency; // same object from App

    @Inject
    ActivityDependency activityDependency; // same object from MainActivity

    @Inject
    FragmentDependency fragmentDepency; // same object from MainFragment

    @Inject
    ChildFragmentDependency childFragmentDepency;

    @Override
    public void onAttach(Context context) {
        AndroidInjection.inject(this);
        super.onAttach(context);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.main_child_fragment, container, false);
    }
}

// MainChildFragmentModule.java
@Module
public abstract class MainChildFragmentModule {
}

// PerActivity.java
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}

// PerFragment.java
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerFragment {
}

// PerChildFragment.java
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerChildFragment {
}

// AppDependency.java
@Singleton
public final class AppDependency {
    @Inject
    AppDependency() {
    }
}

// ActivityDependency.java
@PerActivity
public final class ActivityDependency {
    @Inject
    ActivityDependency() {
    }
}

// FragmentDependency.java
@PerFragment
public final class FragmentDependency {
    @Inject
    FragmentDependency() {
    }
} 

// ChildFragmentDependency.java
@PerChildFragment
public final class ChildFragmentDependency {
    @Inject
    ChildFragmentDependency() {
    }
}
Run Code Online (Sandbox Code Playgroud)

有关@ContributesAndroidInjector上面提到的完整的dagger.android 2.11设置指南和自定义范围,请阅读本文.