我正在尝试了解Dagger 2.11中包含的dagger.android框架。我写了一个实现一些范围的示例代码,@ Singleton,@ ActivityScope和@FragmentScope。
我的Activity有一个片段,片段有一个Toy对象。我希望MainFragment属于Activity Scope,而Toy对象属于Fragment范围。
但我有一个错误,你能帮帮我吗?问题是什么? :
错误:(22,8)错误:[dagger.android.AndroidInjector.inject(T)] 无法提供com.example.user.daggerapplication4.Models.Toy 没有@ Provide-annotated方法。 com.example.user.daggerapplication4.Models.Toy注入 com.example.user.daggerapplication4.ui.MainFragment.toy 注入com.example.user.daggerapplication4.ui.MainFragment com.example.user.daggerapplication4.ui.MainActivity.injectedFragment com.example.user.daggerapplication4.ui.MainActivity注入 dagger.android.AndroidInjector.inject(arg0)带匹配的绑定 密钥存在于组件中: com.example.user.daggerapplication4.ui.MainActivityModule_BindMainFragment.MainFragmentSubcomponent
AppComponent and Module:
@Singleton
@Component(modules = {
AndroidInjectionModule.class,
AppModule.class,
ActivityBuilder.class
})
public interface AppComponent extends AndroidInjector<DaggerSample4Application> {
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<DaggerSample4Application> {}
}
@Module
public class AppModule {
}
@Module
public abstract class ActivityBuilder {
@ActivityScoped
@ContributesAndroidInjector(modules = MainActivityModule.class)
abstract MainActivity bindMainActivity();
}
范围:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface FragmentScoped {}
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScoped {}
ActivityModule和FragmentModule
@Module()
public abstract class MainActivityModule {
@FragmentScoped
@ContributesAndroidInjector(modules = MainFragmentModule.class)
abstract MainFragment bindMainFragment();
}
@Module
public class MainFragmentModule {
@Provides
@FragmentScoped
Toy provideToy()
{
return new Puzzle();
}
}
模型类:
public interface Toy {
public String play();
}
public class Puzzle implements Toy {
@Override
public String play() {
Log.v("DaggerSample","Play with Puzzle");
return "Play with Puzzle";
}
}
MainActivity和MainFragment
public class MainActivity extends DaggerAppCompatActivity {
@Inject
MainFragment injectedFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainFragment mainFragment = (MainFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
// injectedFragment = new MainFragment();
if (mainFragment == null) {
mainFragment = injectedFragment;
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.contentFrame, mainFragment);
transaction.commit();
}
}
}
public class MainFragment extends DaggerFragment {
private Button btnBuy;
private TextView textResult;
@Inject
Toy toy;
@Inject
public MainFragment()
{
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_main, container, false);
btnBuy = root.findViewById(R.id.btnBuy);
textResult = root.findViewById(R.id.textRresult);
btnBuy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showMessage(toy.play());
}
});
return root;
}
public void showMessage(String message) {
textResult.setText(message);
}
}
如果您想调查代码,可以使用此link
进行访问答案 0 :(得分:0)
我认为使用界面时最好使用@Binds。 尝试以下方法。
@Module
public class MainFragmentModule {
@FragmentScoped
@Binds
public abstract Toy bindToy(Puzzle puzzle);
}
public class Puzzle implements Toy {
@Inject
public Puzzle(){
}
@Override
public String play() {
Log.v("DaggerSample","Play with Puzzle");
return "Play with Puzzle";
}
}
答案 1 :(得分:0)
您有一些错误可以在代码中修复,以使您的项目得以编译。但是首先,高效Dagger的经验法则-始终喜欢使用@Binds抽象方法将模块作为抽象类,或者如果使用静态@Provides方法则不可能将其作为抽象类。这意味着您需要使AppModule成为抽象类,否则您的项目将无法按照您在此处发布的代码进行编译。
代码无法编译的主要原因是因为Puzzle没有使用@Inject注释的构造函数:
public class Puzzle implements Toy {
@Inject // Add this
public Puzzle() {
}
@Override
public String play() {
Log.v("DaggerSample","Play with Puzzle");
return "Play with Puzzle";
}
}
接下来,您需要对该模块进行以下更改:
@Module
public class MainFragmentModule { // Make this class abstract
@Provides // Change this to @Binds instead
@FragmentScoped
Toy provideToy() // Change this method to look like this below method
{
return new Puzzle();
}
@Binds
@FragmentScoped
abstract Toy bindPuzzle(Puzzle puzzle);
}
如果您还有其他实现要注入的Toy接口的类,则必须使用限定符(@Named注释)来告诉Dagger注入哪种实现。
您无法将片段插入托管它的活动。相反,您必须创建片段并使用片段管理器添加它。
public class MainActivity extends DaggerAppCompatActivity {
@Inject // Remove this
MainFragment injectedFragment; // And this if you don't use this field
您不能使用@Inject注释片段构造函数。 Fragment是一个Android组件,并且无法通过构造函数注入来注入Android组件。注入Android组件的唯一方法是通过成员注入,如果您的片段继承自DaggerFragment,则已经为您完成了注入。请注意,如果您使用的是支持库片段,请确保使用支持包中的DaggerFragment变体。
您尚未包含DaggerSample4Application代码,因此我无法确定您在此处是否做错了什么,但是要点是,此类需要扩展DaggerApplication并实现一些方法。我有一个完整的工作示例,您可以签出: https://github.com/Nimrodda/dagger-androidinjector 这是我撰写的有关Dagger Android注入https://android.jlelse.eu/android-and-dagger-2-10-androidinjector-5e9c523679a3的文章的源代码 我强烈建议您检查一下以更好地理解。