이렇게 data를 줄줄이 달아보자. 이번엔 Databinding을 사용해서.
RecyclerView는 data가 늘어나고 줄어들 때
리스트뷰 형태로 보여주기 유연한 View이지만
data 포맷이 바뀌면 매번마다 어댑터를 손봐야하는 불편함이 있다.
이를 개선하기 위해 Databinding을 사용하여
RecyclerView를 이용해보기로 하였다.
1. 줄줄이 엮어줄 Item부터 - MyItem.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class MyItem { boolean selectItem; String name; String mydate; public ApprovalItem() { } public ApprovalItem(boolean selectItem, String name, String mydate) { this.selectItem = selectItem; this.name = name; this.mydate = mydate; } // 생략 // Getter, Setter } | cs |
item_my.xml은 생략하겠다.
위 요소가 들어갈 TextView를 자유롭게 만들면 된다.
2. 주인공 RecyclerView 등장 - MyFragment.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <import type="android.databinding.ObservableArrayList" /> <import type="io.truecoupon.app.content.my.MyItem" /> <variable name="myList" type="ObservableArrayList<MyItem>" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".content.my.MyFragment"> <!-- 생략 --> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview_my_list" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutManager="android.support.v7.widget.LinearLayoutManager" app:item="@{myList}"/> </LinearLayout> </layout> | cs |
ObservableArrayList를 사용한 이유.
UI가 변경될 때, data도 바로 변경되고 반대로도 가능하게 하기 위해서.
11번째 줄의 <variable>은 30번째 줄에 사용된다.
adapter에서 편하게 item을 list에 넣을 수 있다.
3. MyFragment.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | public class MyFragment extends BaseFragment<MyPresenter.MyUi> implements MyPresenter.MyUi { public static String TAG = "MyFragment"; private ObservableArrayList<MyItem> myItems; private MyAdapter mAdapter; private MyPresenter mPresenter; // 생략 // 자체적으로 만든 Code // 무시해도 좋다. @Override protected View createRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container) { return inflater.inflate(R.layout.fragment_my, container, false); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); FragmentMyBinding binding = DataBindingUtil .inflate(inflater, R.layout.fragment_my, container, false); // Sample date : "M", "20180801"... todo : remove soon mPresenter = new MyPresenter(); // 생략 mPresenter.mockGetMyList("M", "20180801"); mAdapter = new MyAdapter(); myItems = new ObservableArrayList<>(); binding.recyclerviewMyList.setAdapter(mAdapter); binding.setMyList(myItems); return binding.getRoot(); } // 생략 } | cs |
앞에서(2번 항목) 레이아웃을 정상적으로 만들었다면
FragmentApprovalBinding을 만들 수 있다.
이제 이 binding으로 간단하게 선언할 뷰들은
편하게 호출할 수 있게 되었다.
여기서는 binding으로 recyclerView를 가지고 와서 setAdapter를 하고
레이아웃의 <variable>로 맞춰진 myList를 set하고 있다.
이것으로 Fragment에서 item을 끼울 준비는 다 했다. (쏘 심플~)
이제 Adapter를 만들자.
4. MyAdapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{ public static String TAG = "MyAdapter"; private List<MyItem> myItems; public MyAdapter() { this.myItems = new ArrayList<>(); } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { ItemMyBinding binding = ItemMyBinding.inflate( LayoutInflater.from(parent.getContext()), parent, false); return new MyViewHolder(binding); } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { MyItem item = myItems.get(position); holder.bind(item); } @Override public int getItemCount() { return myItems.size(); } void setItem(List<MyItem> items) { if (items != null) { this.myItems = items; notifyDataSetChanged(); } } @BindingAdapter("bind:item") public static void bindItem(RecyclerView recyclerView, ObservableArrayList<MyItem> items) { MyAdapter adapter = (MyAdapter) recyclerView.getAdapter(); // 생략 if (adapter != null) { adapter.setItem(items); } } class MyViewHolder extends RecyclerView.ViewHolder { ItemMyBinding binding; public MyViewHolder(ItemMyBinding binding) { super(binding.getRoot()); this.binding = binding; } // item_my.xml : <variable> 정보를 취함 void bind(MyItem item) { String price = String.format("%,d", 20000); // 생략 binding.setVariable(BR.my, item); binding.setVariable(BR.price, price); } } } | cs |
먼저 1번 항목에서 안내한 item_my.xml에 layout 태그를 포함한 data binding 준비가 되어 있어야 한다.
그래야 viewholder를 만들기 위한 ItemMyBinding을 생성할 수 있다.
그냥 넘어가려고 했지만 언급해야 덜 찝찝할거 같아서 아래에 공유한다.
item_my.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="my" type="io.truecoupon.app.content.my.MyItem"/> <variable name="price" type="String"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- 내용은 item_my.java를 참고하여 알아서 채우시길 --> </LinearLayout> </layout> | cs |
자... item 준비도 완료되었다. 다시 adapter로 돌아가보자.
onBindViewHolder에서 item을 bind하기 위해 MyViewHolder 아래에 bind 메소드를 추가했다.
BR 클래스로 <variable> 변수명을 찾아서 bind되는 과정이다.
Databinding으로 인해 쉬원진 것 중 하나가 바로 @BindingAdapter 이다.
"bind:item"이라고 되어 있는 부분은 fragment.xml에서 본 app:item="@{myList}"이다.
adapter에서 recyclerView 위에 item을 바로 set할 수 있게
databinding에서 이 어노테이션을 제공하고 있다.
Presenter는 서버와 통신하는 부분이라 이번에 다룰 주제와 밀접하지가 않다.
그래서 Presenter 부분은 생략한다.
* 주의사항1
RecyclerView에는 data를 쌓기 위한 레이아웃 형태를 아래처럼 만들어 줘야 한다.
1 2 3 | binding.recyclerviewMyList.setLayoutManager( new LinearLayoutManager(getActivity(), LinearLayout.VERTICAL, false) ); | cs |
하지만 더 간단하게 할 수 있는 방법이 있다.
아래처럼 xml에서 바로 layoutManager를 처리할 수 있다.
위 샘플코드에는 아래 형태로 되어 있다.
1 2 3 4 5 6 | <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview_approval_list" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutManager="android.support.v7.widget.LinearLayoutManager" app:item="@{approvalList}"/> | cs |
* 주의사항2
만약 아래와 같은 에러를 발견한다면
@BindingAdapter 메소드에 Static으로 적용되어 있지 않았기 때문이다.
1 2 3 4 5 6 | java.lang.IllegalStateException: Required DataBindingComponent is null in class FragmentApprovalBinding. A BindingAdapter in (pkg명 생략).MyAdapter is not static and requires an object to use, retrieved from the DataBindingComponent. If you don't use an inflation method taking a DataBindingComponent, use DataBindingUtil.setDefaultComponent or make all BindingAdapter methods static. | cs |
참고 자료
'Android, iOS' 카테고리의 다른 글
버튼에서 본 애니메이션 효과. 나도 해보고 싶다. (0) | 2018.08.08 |
---|---|
날짜 데이터를 String으로 받았다. Format은? Sorting은? (0) | 2018.08.06 |
Toolbar를 내 맘대로 만들고 싶드아아아ㅏㅏㅏ (0) | 2018.07.31 |
Custom Tab 만들기 (0) | 2018.07.27 |
안드로이드 디바이스의 로컬 DB파일 가져온 후기 (0) | 2018.07.25 |
Comment