android - 如何使用 dagger2 将 Activity 注入(inject) Adapter

标签 android dagger-2

Android Studio 3.0 金丝雀 8

我正在尝试将我的 MainActivity 注入(inject)我的适配器。然而,我的解决方案工作正常,但我认为它有代码味道,而不是正确的方法。

我的适配器 fragment 看起来像这样,但我不喜欢的是我必须将 Activity 转换为 MainActivity:

public class RecipeAdapter extends RecyclerView.Adapter<RecipeListViewHolder> {
    private List<Recipe> recipeList = Collections.emptyList();
    private Map<Integer, RecipeListViewHolderFactory> viewHolderFactories;
    private MainActivity mainActivity;

    public RecipeAdapter(Activity activity, Map<Integer, RecipeListViewHolderFactory> viewHolderFactories) {
        this.recipeList = new ArrayList<>();
        this.viewHolderFactories = viewHolderFactories;
        this.mainActivity = (MainActivity)activity;
    }

    @Override
    public RecipeListViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        /* Inject the viewholder */
        final RecipeListViewHolder recipeListViewHolder = viewHolderFactories.get(Constants.RECIPE_LIST).createViewHolder(viewGroup);

        recipeListViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /* Using the MainActivity to call a callback listener */
                mainActivity.onRecipeItemClick(getRecipe(recipeListViewHolder.getAdapterPosition()));
            }
        });

        return recipeListViewHolder;
    }
}

在我的模块中,我在模块的构造函数中传递 Activity 并将其传递给适配器。

@Module
public class RecipeListModule {
    private Activity activity;

    public RecipeListModule() {}

    public RecipeListModule(Activity activity) {
        this.activity = activity;
    }

    @RecipeListScope
    @Provides
    RecipeAdapter providesRecipeAdapter(Map<Integer, RecipeListViewHolderFactory> viewHolderFactories) {
        return new RecipeAdapter(activity, viewHolderFactories);
    }
}

在我的应用程序类中,我创建了组件,并为适配器使用了一个子组件。在这里,我必须传递我不确定是个好主意的 Activity。

@Override
public void onCreate() {
    super.onCreate();

    applicationComponent = createApplicationComponent();
    recipeListComponent = createRecipeListComponent();
}

public BusbyBakingComponent createApplicationComponent() {
    return DaggerBusbyBakingComponent.builder()
            .networkModule(new NetworkModule())
            .androidModule(new AndroidModule(BusbyBakingApplication.this))
            .exoPlayerModule(new ExoPlayerModule())
            .build();
}

public RecipeListComponent createRecipeListComponent(Activity activity) {
    return recipeListComponent = applicationComponent.add(new RecipeListModule(activity));
}

我注入(inject)的 fragment 是这样的:

@Inject RecipeAdapter recipeAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ((BusbyBakingApplication)getActivity().getApplication())
                .createRecipeListComponent(getActivity())
                .inject(this);
    }

尽管上面的设计有效,但我认为这是一种代码味道,因为我必须将 Activity 转换为 MainActivity。我使用 Activity 的原因是我想让这个模块更通用。

不知道有没有更好的办法

=============== 使用界面更新

界面

public interface RecipeItemClickListener {
    void onRecipeItemClick(Recipe recipe);
}

实现

public class RecipeItemClickListenerImp implements RecipeItemClickListener {
    @Override
    public void onRecipeItemClick(Recipe recipe, Context context) {
        final Intent intent = Henson.with(context)
                .gotoRecipeDetailActivity()
                .recipe(recipe)
                .build();

        context.startActivity(intent);
    }
}

在我的模块中,我有以下供应商

@Module
public class RecipeListModule {
    @RecipeListScope
    @Provides
    RecipeItemClickListener providesRecipeItemClickListenerImp() {
        return new RecipeItemClickListenerImp();
    }

    @RecipeListScope
    @Provides
    RecipeAdapter providesRecipeAdapter(RecipeItemClickListener recipeItemClickListener, Map<Integer, RecipeListViewHolderFactory> viewHolderFactories) {
        return new RecipeAdapter(recipeItemClickListener, viewHolderFactories);
    }
}

然后我通过 RecipeAdapter 中的构造函数注入(inject)来使用它

public class RecipeAdapter extends RecyclerView.Adapter<RecipeListViewHolder> {
    private List<Recipe> recipeList = Collections.emptyList();
    private Map<Integer, RecipeListViewHolderFactory> viewHolderFactories;
    private RecipeItemClickListener recipeItemClickListener;

    @Inject /* IS THIS NESSESSARY - AS IT WORKS WITH AND WITHOUT THE @Inject annotation */
    public RecipeAdapter(RecipeItemClickListener recipeItemClickListener, Map<Integer, RecipeListViewHolderFactory> viewHolderFactories) {
        this.recipeList = new ArrayList<>();
        this.viewHolderFactories = viewHolderFactories;
        this.recipeItemClickListener = recipeItemClickListener;
    }

    @Override
    public RecipeListViewHolder onCreateViewHolder(final ViewGroup viewGroup, int i) {
        /* Inject the viewholder */
        final RecipeListViewHolder recipeListViewHolder = viewHolderFactories.get(Constants.RECIPE_LIST).createViewHolder(viewGroup);

        recipeListViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                recipeItemClickListener.onRecipeItemClick(getRecipe(recipeListViewHolder.getAdapterPosition()), viewGroup.getContext());
            }
        });

        return recipeListViewHolder;
    }
}

只有一个问题,RecipeAdapter 中的构造函数需要@Inject 注释。无论是否使用@Inject,它都可以工作。

最佳答案

不要将 Activity 传递到 Adapters - 这是一个非常糟糕的做法。

仅注入(inject)您关心的字段。

在您的示例中:将接口(interface)传递到适配器以跟踪项目点击。

关于android - 如何使用 dagger2 将 Activity 注入(inject) Adapter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45419560/

相关文章:

java - Dagger 2 模块与子组件

android - 使用 Flow + Mortar + Dagger 2 保存/恢复屏幕状态的首选方法是什么?

kotlin - Dagger 和 Kotlin 。 Dagger 不生成组件类

android - READ_PHONE_NUMBERS 在 android O 下不工作

Android 服务 mysql - 检查数据库更改

android - 如何在 Android 上创建文本文件并将数据插入该文件

android - 仅用于基本 Activity 的依赖注入(inject)会使子 Activity 崩溃

android - WifiManager.getScanResults() - 说明(自动扫描、 sleep 等)

android - 以编程方式设置首选项的默认值

java - 错误: @dagger. 使用了android.ContributesAndroidInjector,但是找不到dagger.android.processor.AndroidProcessor