================ 2017.06.07 수정 ================
https://stackoverflow.com/documentation/android/169/recyclerview/18296/recyclerview-with-databinding#t=201706071246198231184 의 ViewHolder 를 적용했다.
얼른 넘어가야하는데, 손이 안 가서 실력이 안 늘고 있는 RecyclerView도 써보자. 아무래도 ListView가 손에 익다보니 쉽고 빠르게 하다보니 RecyclerView는 진짜 꼭 필요할 때만 사용하는데, 새로 나온 걸 좋아하는 성격상 뭔가 마음 속 한 구석이 불편하다. 성능도 더 좋아졌고, 커스터마이징하기도 좋은데, 왜 손이 안 가는지 모르겠다. 이번에 하는 프로젝트는 ListView를 쓰지않고 모두 다 RecyclerView를 써봐야겠다.
먼저 관련 라이브러리를 추가한다.
compile 'com.android.support:design:25.3.1'
RecyclerView는 기본적으로 행 구분선이 없기 때문에 데코레이터를 추가해줘야 한다.
public class DividerLineDecoratorViewModel implements BaseViewModel{ public final ObservableField<DividerItemDecoration> decorator = new ObservableField<>(); public Context context; @Override public void onCreate() { decorator.set(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL)); } @Override public void onResume() {} @Override public void onPause() {} @Override public void onDestroy() {} }
화면을 그린다.
여기에는 이전의 ListView 예제에서 사용한 UsersViewModel을 그대로 사용한다.
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="model" type="kr.susemi99.testmvvm.list_view.UsersViewModel"/> <variable name="decorator" type="kr.susemi99.testmvvm.recycler_view.DividerLineDecoratorViewModel"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{()-> model.newUser()}" android:text="add"/> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" app:items="@{model.users}" app:decorator="@{decorator.decorator}" app:layoutManager="LinearLayoutManager"/> </LinearLayout> </layout>
만약 레이아웃에서 RecyclerView의 방향을 Vertical이 아닌 Horizontal로 하고 싶을 땐 어떻게 해야하는지는 못 찾았다.
RecyclerView의 한 행을 표시할 때 사용할 뷰홀더를 만들어 준다.
public class BindingViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder { private final T binding; public BindingViewHolder(View view) { super(view); this.binding = (T) DataBindingUtil.bind(view); } public T binding() { return binding; } }
이 클래스는 다른 RecyclerView에서도 바로 사용할 수 있다.
RecyclerView에서 사용할 어댑터를 만든다.
public class UserRecyclerViewAdapter extends RecyclerView.Adapter<BindingViewHolder<ListItemUserBinding>> { private ArrayList<UserViewModel> users = new ArrayList<>(); public void add(ArrayList<UserViewModel> users) { for (UserViewModel user : users) { if (!this.users.contains(user)) { this.users.add(user); notifyItemInserted(this.users.size() - 1); } } } @Override public BindingViewHolder<ListItemUserBinding> onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); return new BindingViewHolder<>(inflater.inflate(R.layout.list_item_user, parent, false)); } @Override public void onBindViewHolder(BindingViewHolder<ListItemUserBinding> holder, int position) { holder.binding().setUser(users.get(position)); holder.binding().setNavigator(navigator); } @Override public int getItemCount() { return users.size(); } }
ListView처럼 notifyDataSetChanged() 를 호출하면 화면이 번쩍거리니까 반드시 notifyItemInserted() 를 호출해야 한다.
액티비티에서는 어댑터와 데코레이터에 관한 정보를 받아서 처리한다.
public class RecyclerActivity extends AppCompatActivity { private UsersViewModel usersViewModel = new UsersViewModel(); private DividerLineDecoratorViewModel decoratorViewModel = new DividerLineDecoratorViewModel(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityRecyclerBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_recycler); binding.setModel(usersViewModel); binding.setDecorator(decoratorViewModel); decoratorViewModel.context = getApplicationContext(); decoratorViewModel.onCreate(); } @BindingAdapter("app:items") public static void setUserList(RecyclerView recyclerView, ArrayList<UserViewModel> users) { UserRecyclerViewAdapter adapter; if(recyclerView.getAdapter() == null) { adapter = new UserRecyclerViewAdapter(); recyclerView.setAdapter(adapter); } else { adapter = (UserRecyclerViewAdapter) recyclerView.getAdapter(); } adapter.add(users); } @BindingAdapter("app:decorator") public static void setDecorator(RecyclerView recyclerView, ObservableField<DividerItemDecoration> decorator) { recyclerView.addItemDecoration(decorator.get()); } }
이런 식으로 잘 나온다.