Skip to main content
 首页 » 编程设计

dagger-2之Dagger 2.11 ContributesAndroidInjector Singleton依赖注入(inject)失败

2024年07月26日32haluo1

我正在探索 Dagger 2.11 中的新 dagger.android。我希望不必创建像 @PerActivity 这样的自定义范围注释。到目前为止,我能够执行以下操作:

1) 定义应用程序范围单例并将它们注入(inject)到事件中。

2) 定义 Activity 范围非单例依赖项,并使用 @ContributesAndroidInjector 将它们注入(inject)到其 Activity 中

我不知道如何让应用程序范围单例和事件范围非单例使用它。

在下面的示例中,我希望我的事件范围 MyActivityDependencyAMyActivityDependencyB 能够访问单例 MyActivityService

以下设置结果:

Error:(24, 3) error: com.example.di.BuildersModule_BindMyActivity.MyActivitySubcomponent (unscoped) may not reference scoped bindings: @Singleton @Provides com.example.MyActivityService com.example.MyActivitySingletonsModule.provideMyActivityService()

这是我的设置。请注意,我定义了单独的 MyActivitySingletonsModuleMyActivityModule 因为我无法在同一模块文件中混合单例和非单例依赖项。

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

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

@Module 
public abstract class MyActivitySingletonsModule { 
    @Singleton 
    @Provides 
    MyActivityService provideMyActivityService() { 
        return new MyActivityService(); 
    } 
} 

@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); 
} 

是否可以在不定义自定义范围注释的情况下完成我想做的事情?

提前致谢!

请您参考如下方法:

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

"My understanding is @ContributesAndroidInjector removes the need for custom annotation and I was able to prove it by using non-singletons defined in the activity scope without any issues."

@ContributesAndroidInjector(在 v2.11 中提供)不会消除对自定义范围的需要。它只是取代了声明 @Subcomponent 类的需要,而这些类不使用 @Subcomponent.Builder 在运行时注入(inject)组件所需的依赖项。看一下 official dagger.android user guide about @ContributesAndroidInjector 中的以下代码片段;

"Pro-tip: If your subcomponent and its builder have no other methods or supertypes than the ones mentioned in step #2, you can use @ContributesAndroidInjector to generate them for you. Instead of steps 2 and 3, add an abstract module method that returns your activity, annotate it with @ContributesAndroidInjector, and specify the modules you want to install into the subcomponent. If the subcomponent needs scopes, apply the scope annotations to the method as well."

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

这里的关键是“如果子组件需要作用域,请将作用域注释也应用到方法中。”

查看以下代码,了解如何使用 @Singleton@PerActivity@PerFragment >@PerChildFragment 使用新的 dagger.android 注入(inject)框架自定义作用域。

// 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() { 
    } 
} 

有关使用 @ContributesAndroidInjector 和上述自定义范围的完整 dagger.android 2.11 设置指南,请阅读 this article .