Dagger2.11 не может быть предоставлен без аннотированного метода @ Provides - PullRequest
0 голосов
/ 01 июня 2018

Я пытаюсь понять структуру dagger.android, включенную в Dagger 2.11.Я написал пример кода, который реализует некоторые области видимости, @Singleton, @ActivityScope и @FragmentScope.

Моя активность имеет фрагмент, а фрагмент имеет игрушечный объект.Я хочу, чтобы MainFragment принадлежал области действия, а объект Toy принадлежал области действия фрагмента.

Но у меня ошибка, не могли бы вы мне помочь, пожалуйста?В чем проблема?:

Ошибка: (22, 8) ошибка: [dagger.android.AndroidInjector.inject (T)] com.example.user.daggerapplication4.Models.Toy не может быть предоставлена ​​без @ Provides-аннотированный метод.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_BindMainFragmentSBindMainFragmentSB

AppComponent и модуль:

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

Если вы хотите исследовать код, вы можете получить доступ по этой ссылке

Ответы [ 2 ]

0 голосов
/ 08 июля 2018

Вам нужно исправить несколько ошибок в своем коде, чтобы ваш проект компилировался.Но сначала, практическое правило для эффективного 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.Фрагмент является компонентом 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 Я настоятельно рекомендую вам ознакомиться с ней, чтобы лучше понять.

0 голосов
/ 01 июня 2018

Я думаю, что при использовании интерфейса лучше использовать @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";
    }
}
...