如果没有@ Provide-annotated方法

时间:2018-05-31 21:17:12

标签: android dagger

我正在尝试了解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

进行访问

2 个答案:

答案 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的文章的源代码 我强烈建议您检查一下以更好地理解。