作者:多盟乄丶 | 来源:互联网 | 2023-01-27 14:08
Android Studio 3.0 Canary 8
我正在尝试将我的MainActivity注入我的适配器.但是,我的解决方案工作正常,但我认为它的代码味道并不是正确的方法.
我的适配器代码段看起来像这样,但我不喜欢这是我必须转换Activity
为MainActivity
:
public class RecipeAdapter extends RecyclerView.Adapter {
private List recipeList = Collections.emptyList();
private Map viewHolderFactories;
private MainActivity mainActivity;
public RecipeAdapter(Activity activity, Map 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并将其传递给Adapter.
@Module
public class RecipeListModule {
private Activity activity;
public RecipeListModule() {}
public RecipeListModule(Activity activity) {
this.activity = activity;
}
@RecipeListScope
@Provides
RecipeAdapter providesRecipeAdapter(Map viewHolderFactories) {
return new RecipeAdapter(activity, viewHolderFactories);
}
}
在我的应用程序类中,我创建组件,我使用SubComponent作为适配器.在这里,我必须通过我不确定是一个好主意的活动.
@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 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 viewHolderFactories) {
return new RecipeAdapter(recipeItemClickListener, viewHolderFactories);
}
}
然后我通过RecipeAdapter中的构造函数注入使用它
public class RecipeAdapter extends RecyclerView.Adapter {
private List recipeList = Collections.emptyList();
private Map viewHolderFactories;
private RecipeItemClickListener recipeItemClickListener;
@Inject /* IS THIS NESSESSARY - AS IT WORKS WITH AND WITHOUT THE @Inject annotation */
public RecipeAdapter(RecipeItemClickListener recipeItemClickListener, Map 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.
1> Yossi Segev..:
不要将活动传递给适配器 - 这是一个非常糟糕的做法.
仅注入您关心的字段.
在您的示例中:将接口传递到适配器以跟踪项目单击.
2> David Medenj..:
如果你需要,MainActivity
那么你也应该提供它.而不是为您的模块Activity
声明MainActivity
.
@Module
public class RecipeListModule {
private MainActivity activity;
public RecipeListModule(MainActivity activity) {
this.activity = activity;
}
}
你的适配器应该只是请求它(非 Android Framework类型的构造函数注入!)
@RecipeListScope
class RecipeAdapter {
@Inject
RecipeAdapter(MainActivity activity,
Map viewHolderFactories) {
// ...
}
}
如果你想要你的模块使用Activity
而不是MainActivity
那么你需要声明一个已经提到过的接口.然后,适配器会将接口声明为其依赖项.
但在某些模块中,您仍然需要将该接口绑定到您的MainActivity
模块,并且一个模块需要知道如何提供依赖项.
// in some abstract module
@Binds MyAdapterInterface(MainActivity activity) // bind the activity to the interface
解决问题的更新部分
只有一个问题,是@Inject
RecipeAdapter中构造函数的注释需求.因为它可以使用或不使用@Inject
.
它没有它,因为你还没有使用构造函数注入.你还在调用构造自己在providesRecipeAdapter()
.作为一般的经验法则 - 如果你想正确使用Dagger - 不要自称new
.如果你new
想问自己是否可以使用构造函数注入.
您显示的相同模块可以编写如下,使用@Binds
绑定实现到接口,并实际使用构造函数注入来创建适配器(这就是为什么我们不必为它编写任何方法!更少的代码到维护,减少错误,更易读的类)
如你所见,我不需要new
自己使用--Dagger会为我创建物体.
public abstract class RecipeListModule {
@RecipeListScope
@Binds
RecipeItemClickListener providesRecipeClickListener(RecipeItemClickListenerImp listener);
}