2016-06-16 2 views
3

Мне интересно, как сделать Databinding и RecyclerView работать вместе. У меня есть класс адаптера определяется следующим образом:Databinding и RecyclerView в приложении для Android

public class RestaurantRecyclerViewAdapter extends RecyclerView.Adapter<RestaurantRecyclerViewAdapter.BindingHolder> { 

    private RestaurantsListViewModel mDataContext; 

    public RestaurantRecyclerViewAdapter(RestaurantsListViewModel vm) { 
     mDataContext = vm; 
    } 


    @Override 
    public BindingHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_restaurant_list_item, parent, false); 
     BindingHolder holder = new BindingHolder(v); 

     return holder; 
    } 

    @Override 
    public void onBindViewHolder(final BindingHolder holder, int position) { 
     final RestaurantListItemViewModel restaurant = mDataContext.getRestaurant(position); 

     holder.getBinding().setVariable(BR.restaurant, restaurant); 
     holder.getBinding().executePendingBindings(); 
    } 

    @Override 
    public int getItemCount() { 
     return mDataContext.getRestaurantsCount(); 
    } 

    public class BindingHolder extends RecyclerView.ViewHolder { 

     private ViewDataBinding binding; 

     public BindingHolder(View rowView) { 
      super(rowView); 
      binding = DataBindingUtil.bind(rowView); 
     } 

     public ViewDataBinding getBinding() { 
      return binding; 
     } 

    } 

} 

Если RestaurantListViewModel обновляется с новыми ресторанами Я хотел бы RecyclerView вновь вынести эти новые объекты. Как я могу это сделать?

EDIT:

@Vladimirs подход представляется разумным, однако у меня возникают проблемы, реализующий метод onBindViewHolder:

public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { 
    final RestaurantListItemViewModel restaurant = restaurants.get(position); 

    holder.getBinding().setVariable(BR.restaurant, restaurant); 
    holder.getBinding().executePendingBindings(); 
} 

Теперь нет getBinding метода.

ответ

3

Вы можете создать адаптер первый

public class RecyclerViewAdapters { 

    @BindingAdapter("items") 
    public static void setItems(RecyclerView view, List<Object> items) { 
     RecyclerView.Adapter<?> adapter = view.getAdapter(); 
     if (adapter instanceof RestaurantRecyclerViewAdapter) { 
      // tell RestaurantRecyclerViewAdapter to set new list of items 
     } else { 
      throw new IllegalArgumentException("RecyclerView.Adapter is not RestaurantRecyclerViewAdapter"); 
     } 
    } 
} 

затем в модели представления

public final ObservableList<Object> items = new ObservableArrayList<>(); 

и, наконец, в XML-макете

<android.support.v7.widget.RecyclerView 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    app:items="@{viewModel.items}" 
    app:layoutManager="LinearLayoutManager"/> 

Это довольно простой способ, который не учитывает частичное изменения элементов, вы можете больше взглянуть на ObservableList и OnListChangedCallback

UPD Как следить за OnListChangedCallback, я думал, что может быть что-то подобное может быть реализовано с помощью адаптера реагировать на точных изменений списка.

public class ObservableListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { 
    ObservableList<Object> list; 

    ObservableList.OnListChangedCallback<ObservableList<Object>> callback = new ObservableList.OnListChangedCallback<ObservableList<Object>>() { 
     @Override 
     public void onChanged(ObservableList<Object> sender) { 
      notifyDataSetChanged(); 
     } 

     @Override 
     public void onItemRangeChanged(ObservableList<Object> sender, int positionStart, int itemCount) { 
      notifyItemRangeChanged(positionStart, itemCount); 
     } 

     @Override 
     public void onItemRangeInserted(ObservableList<Object> sender, int positionStart, int itemCount) { 
      notifyItemRangeInserted(positionStart, itemCount); 
     } 

     @Override 
     public void onItemRangeMoved(ObservableList<Object> sender, int fromPosition, int toPosition, int itemCount) { 
      notifyItemRangeRemoved(fromPosition, itemCount); 
      notifyItemRangeInserted(toPosition, itemCount); 
     } 

     @Override 
     public void onItemRangeRemoved(ObservableList<Object> sender, int positionStart, int itemCount) { 
      notifyItemRangeRemoved(positionStart, itemCount); 
     } 
    }; 

    public ObservableListAdapter(@NonNull ObservableList<Object> list) { 
     this.list = list; 
     this.list.addOnListChangedCallback(callback); 
    } 

    @Override 
    public int getItemCount() { 
     return list.size(); 
    } 

    @Override 
    public long getItemId(int position) { 
     return position; 
    } 
} 
+0

Я немного смущен. Где я должен поместить метод 'setItems'? –

+0

В любом классе вы хотели бы. Я создал класс RecyclerViewAdapters и поместил туда эту функцию. Я попробовал себя сейчас, посмотрю обновленную вторую часть вопроса. Он работает как шарм, не нужен xml, просто передайте свой ObservableList конструктору. –

+0

Следующий вопрос - мне нужно переопределить метод 'onBindViewHolder', однако я не знаю, как это сделать, используя ваш подход. Взгляните на мой обновленный вопрос. –