在Android

时间:2016-06-30 14:38:29

标签: android android-fragments design-patterns interface listener

所以我有一个活动。 Activity包含一个带有选项卡的ViewPager,每个选项卡中都包含一个Fragment。 Fragments本身各有一个RecyclerView。我需要将RecyclerView适配器的更改传达给活动。

目前,我正在使用侦听器模式并使用每个组件之间的接口进行通信。我在RecyclerView的适配器和包含它的Fragment之间有一个接口。然后是一个从Fragment到ViewPager的FragmentStatePagerAdapter的接口,它创建了所有的Fragments。 ViewPager的适配器和托管ViewPager的Activity之间还有一个接口。我觉得所有组件的界面太多了,因为它们的结构如何。

目前我没有遇到这样的问题,但我认为由于所有嵌套组件,监听器模式就像反模式一样。我认为层次结构将使得将来很难进行代码更改,而不是创建独立的组件。

我是正确地做了还是有更好的方法呢?这是一个我应该使用事件总线或观察者模式的情况(如果是的话,你可以指出一些例子,其中有人克服了使用它的类似问题)?

注意:如果重要,我需要它来维护活动中的全局对象,比如我可以添加或删除项目的购物车,这些项目存在于RecyclerView的适配器中,我可以将其添加到购物车并且还增加或减少特定项目的计数。 ViewPager和Tabs有助于将这些项目分成不同的类别。

编辑1:有些代码试用了@ LucaNicoletti的方法 - 我跳过了一个级别,即ViewPager的FragmentStatePagerAdapter级别。我想这应该不重要,并删除一些其他代码以保持小。

MainActivity:

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

2 个答案:

答案 0 :(得分:1)

我的评论是:

  

您应该/可以做什么?拥有一个全局数据仓库,用于保存购物车和与其相关的监听器。像单例一样,像ShoppingCart.getInstance()。addListener(this);和ShoppingCart.getInstance()。addItem(new Item(id));

  

是。这就是我所建议的。不要忘记,这个Singleton永远不会持有Context或Activity,因为你不想泄漏内存,所以总是调用removeListener。在我看来,它会降低依赖性,因为所有视图控制器只与数据模型交互

我会添加一些代码作为正确的答案。

下面是一个非常粗略的,按心脏代码输入,但它应该给出一个想法。所有UI元素仅与数据相关联,而不是彼此相关。

类似的东西可以通过为纯数据对象提供开箱即用的observable模式的库来实现。

public class ShoppingCart {

   private ShoppingCart single;
   private static void init(){
       .. init single if not null
   }

   private List<Item> items = new ArrayList<>();
   public int numberOfItems;
   public long totalPrice;

   private static void addItem(Item item){
      init()
      single.items.add(item);
      single.numberOfItems++;
      single.totalPrice+=item.price;
      dispatchChange();
   }

   private static void removeItem(Item item){
      init();
      single.numberOfItems--;
      single.totalPrice-=item.price;
      dispatchChange();
      single.items.remove(item);
   }

  private void dispatchChange(){
      // TODO: write real loop here
      for(single.listeners) listener.onCartChanged(single.cart);
  }
  public interface Listener {
      void onCartChanged(ShoppingCart cart);
  }
  private List<Listener> listeners = new ArrayList<>();
  // TODO: addListener and removeListener code

  public static class Item {
    String id;
    String name;
    long price;
  }

}

答案 1 :(得分:0)

要在组件(ActivityFragment)之间进行通信,您必须使用事件总线。 在android中,您可以选择:

A blog来解释这一点。