【发布时间】:2016-06-30 14:38:28
【问题描述】:
所以我有一个活动。 Activity 托管一个带有选项卡的 ViewPager,每个选项卡都包含一个 Fragment。 Fragments 本身每个都有一个 RecyclerView。我需要将 RecyclerView 的适配器的更改传达给活动。
目前,我正在使用侦听器模式并使用每个组件之间的接口进行通信。即我在 RecyclerView 的适配器和持有它的 Fragment 之间有一个接口。然后是从 Fragment 到创建所有 Fragment 的 ViewPager 的 FragmentStatePagerAdapter 的接口。 ViewPager 的适配器和承载 ViewPager 的 Activity 之间还有 1 个接口。我觉得所有组件的接口太多了,因为它们的结构。
目前我没有遇到这样的问题,但我认为由于所有嵌套组件,侦听器模式就像一个反模式。与其创建独立的组件,我认为层次结构将使将来难以进行代码更改。
我做得正确还是有更好的方法?这是我应该使用事件总线或观察者模式的情况吗(如果是,你能指出一些例子,有人使用它克服了类似的问题)吗?
注意:如果重要,我需要它来维护 Activity 中的全局对象,例如购物车,我可以在其中添加或删除项目,这些项目存在于 RecyclerView 的适配器中,我可以将其添加到购物车并且还增加或减少特定项目的计数。 ViewPager 和 Tabs 有助于将这些项目分成不同的类别。
编辑 1:一些代码尝试了@LucaNicoletti 的方法 - 我跳过了一个级别,即 ViewPager 的 FragmentStatePagerAdapter 级别。我想这应该没关系,并剥离了一些其他代码以保持它的小。
主活动:
public class MainActivity extends AppCompatActivity implements View.OnClickListener, FoodAdapter.OnFoodItemCountChangeListener {
@Override
public void onFoodItemDecreased(FoodItemModel foodItemModel, int count) {
Log.d("Test", "Dec");
}
@Override
public void onFoodItemIncreased(FoodItemModel foodItemModel, int count) {
Log.d("Test", "Inc");
}
// Other methods here
}
承载适配器的片段:
public class FoodCategoryListFragment extends Fragment implements FoodAdapter.OnFoodItemCountChangeListener {
// Other boring variables like recyclerview and layout managers
FoodAdapter foodAdapter;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Other boring intializations for recyclerview and stuff
// I set the click listener here directly on the adapter instance
// I don't have this adapter instance in my activity
foodAdapter.setOnFoodItemClickListener(this);
rvFoodList.setAdapter(foodAdapter);
}
}
最底层的适配器类:
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {
private OnFoodItemCountChangeListener onFoodItemCountChangeListener;
private List<FoodItemModel> foodItems;
// The interface
public interface OnFoodItemCountChangeListener {
void onFoodItemIncreased(FoodItemModel foodItemModel, int count);
void onFoodItemDecreased(FoodItemModel foodItemModel, int count);
}
// This is called from the fragment since I don't have the adapter instance
// in my activty
public void setOnFoodItemClickListener(OnFoodItemCountChangeListener onFoodItemCountChangeListener) {
this.onFoodItemCountChangeListener = onFoodItemCountChangeListener;
}
// Other boring adapter stuff here
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bMinus:
onFoodItemCountChangeListener.onFoodItemDecreased(foodItems.get(getAdapterPosition()),
Integer.parseInt(etCounter.getText().toString()));
}
break;
case R.id.bPlus:
onFoodItemCountChangeListener.onFoodItemIncreased(foodItems.get(getAdapterPosition()),
Integer.parseInt(etCounter.getText().toString()));
}
break;
}
}
}
【问题讨论】:
-
如果中间的监听器只是将动作转发到更高级别,则将接口移除到该级别,并使用更高的接口
-
您应该/可以做的是拥有一个全局数据存储库,其中包含与更改相关联的购物车和侦听器。像一个单例,像
ShoppingCart.getInstance().addListener(this);和ShoppingCart.getInstance().addItem(new Item(id)); -
@LucaNicoletti 但是为了设置监听器,我需要在最高级别有一个最低级别的实例来设置它。我将上述实例保持在中等水平。就像我的 Activity 跟踪 ViewPager 并反过来跟踪具有适配器的 Fragments。 Activity 没有要在其上设置侦听器的 Adapter 实例。如果根据听众模式,这听起来有误,我深表歉意。
-
在最底层声明一个接口:LowestLevelDelegate,将其标记为public,并在你的activity中实现这个接口。您的活动将实现此接口内的方法,但最低级别的片段/适配器将通过具有接口的实例来调用接口方法
-
@Budius 你是在建议我维持一个单身人士以避免听众大惊小怪吗? (奇怪我怎么没想到!:|)我需要再考虑一下,我想这会增加使用 ShoppingCart 实例的每个组件与 ShoppingCart 本身之间的依赖关系。如果我错了,请纠正我。
标签: android android-fragments design-patterns interface listener