코틀린 기반으로 코드를 구현하면 쉽게 샘플 예제를 찾을 수 있다. 하지만 Java 코드 기반 자료는 찾기가 쉽지 않다.
제일 빠르게 찾는 방법은 유투브 동영상에서 검색하는 것이다.
https://www.youtube.com/watch?v=xPPMygGxiEo
이 동영상 강좌 시청하면서 링크된 Github 샘플 자료를 참고하면 이해하는데 훨씬 빠를 것이다.
ListAdapter는 RecyclerView에 쓸 수 있는 어댑터이다.
기존의 어댑터와는 다르게 DiffUtil을 사용하여 비동기식 처리를 할 수 있다.
기존의 기본 어댑터는 mAdapter.notifyDataSetChanged(); 메소드를 사용하여 리스트의 변경처리를 했었는데,
ListAdapter에서는 submitList(...) 를 사용하여 리스트가 변경되었음을 어댑터에게 알려줄 수 있다.
DiffUtil 클래스는 oldItem, newItem의 두 데이터셋을 비교하여 값이 변경된 부분만을 RecyclerView에게 알려줄 수 있다.
비교 결과, 다르다고 판단된 아이템 항목만 교체를 진행한다. 이것이 중요한 포인트이다.
아래 샘플 예제는 MVVM 패턴을 고려하여 작성한 코드는 아니며, 내용 숙지 차원에서 수정 부분 중심으로 적어둔다.
Java 코드로 구현한 Class
- 일단 코드가 참 길다.
- DiffUtil.ItemCallback 메소드 구현을 이곳에 하는 예제도 있고 RecyclerViewApdater 에 구현한 예제도 있다.
import android.graphics.Movie;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import java.util.Objects;
public class Address_Item {
private String idx;
private String userNM;
private String mobileNO;
private String telNO;
private String photo;
private Boolean checkBoxState;
public Address_Item(String idx, String userNM, String mobileNO, String telNO, String photo, Boolean checkBoxState) {
this.idx = idx;
this.userNM = userNM;
this.mobileNO = mobileNO;
this.telNO = telNO;
this.photo = photo;
this.checkBoxState = checkBoxState;
}
public String getIdx() {
return idx;
}
public void setIdx(String idx) {
this.idx = idx;
}
public String getUserNM() {
return userNM;
}
public void setUserNM(String userNM) {
this.userNM = userNM;
}
public String getMobileNO() {
return mobileNO;
}
public void setMobileNO(String mobileNO) {
this.mobileNO = mobileNO;
}
public String getTelNO() {
return telNO;
}
public void setTelNO(String telNO) {
this.telNO = telNO;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public Boolean getCheckBoxState() {
return checkBoxState;
}
public void setCheckBoxState(Boolean checkBoxState) {
this.checkBoxState = checkBoxState;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address_Item that = (Address_Item) o;
return Objects.equals(idx, that.idx) && Objects.equals(userNM, that.userNM) && Objects.equals(mobileNO, that.mobileNO) && Objects.equals(telNO, that.telNO) && Objects.equals(photo, that.photo) && Objects.equals(checkBoxState, that.checkBoxState);
}
@Override
public int hashCode() {
return Objects.hash(idx, userNM, mobileNO, telNO, photo, checkBoxState);
}
public static DiffUtil.ItemCallback<Address_Item> itemCallback = new DiffUtil.ItemCallback<Address_Item>() {
@Override
public boolean areItemsTheSame(@NonNull Address_Item oldItem, @NonNull Address_Item newItem) {
return oldItem.getIdx().equals(newItem.getIdx());
}
@Override
public boolean areContentsTheSame(@NonNull Address_Item oldItem, @NonNull Address_Item newItem) {
return oldItem.equals(newItem);
}
};
}
|
코드가 너무 긴 관계로 Java 에서 코틀린으로 코드를 변환시켰다.
그 다음에 var 변수 초기화 부분의 코드를 약간 수정했다.
이것은 Java 로 구현된 코드와 혼용 사용하는 Class 이다.
import android.os.Parcelable
import androidx.recyclerview.widget.DiffUtil
import kotlinx.parcelize.Parcelize
import java.util.*
@Parcelize
class Address_Item(
// 결과를 받을 모델 (ArrayList 에 저장하므로 val 로 선언하면 안된다)
// 서버 SQL의 칼럼명과 일치하게 작성해야 한다.
var idx: String="",
var userNM: String="",
var mobileNO: String?=null,
var telNO: String?=null,
var photo: String?=null,
var checkBoxState: Boolean
) : Parcelable {
override fun equals(o: Any?): Boolean {
if (this === o) return true
if (o == null || javaClass != o.javaClass) return false
val that = o as Address_Item
return idx == that.idx && userNM == that.userNM && mobileNO == that.mobileNO && telNO == that.telNO && photo == that.photo && checkBoxState == that.checkBoxState
}
override fun hashCode(): Int {
return Objects.hash(idx, userNM, mobileNO, telNO, photo, checkBoxState)
}
companion object {
@JvmField
var itemCallback: DiffUtil.ItemCallback<Address_Item> =
object : DiffUtil.ItemCallback<Address_Item>() {
override fun areItemsTheSame(oldItem: Address_Item, newItem: Address_Item): Boolean {
return oldItem.idx == newItem.idx
}
override fun areContentsTheSame(oldItem: Address_Item, newItem: Address_Item): Boolean {
return oldItem == newItem
}
}
}
}
|
AddressActivity.java
- 기존 파일에서 객체를 생성하는 코드는 주석처리했다.
- Adpater 로 데이터를 전달하는 부분은 mAdpater.submitList(전달변수);
이 코드는 서버에서 자료를 가져온 후 데이터를 넘기는 곳에 적어주면 된다.
private void buildRecyclerView() {
mRecyclerView = binding.rvAddress;
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager manager = new LinearLayoutManager(mContext);
//mAdapter = new AddressViewAdapter(mContext,searchItemList); // 객체 생성
mAdapter = new AddressListAdapter(mContext, Address_Item.itemCallback); // DiffUtil을 넣은 어댑터를 생성
//mAdapter.submitList(searchItemList); // 서버에서 데이터를 가져온 이 후 코드에 추가하면 된다.
DividerItemDecoration decoration = new DividerItemDecoration(mContext,manager.getOrientation());
mRecyclerView.addItemDecoration(decoration);
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(this);
}
|
AddressListAdapter.java
- 기존 RecyclerView.Adapter 대신에 ListAdapter<T, VH> 를 상속한다.
- RecyclerView 가 화면에 표시할 데이터 타입 Address_Item 을 추가한다.
- 이렇게 변경하고 나면 생성자 부분이 에러가 발생한다. 자동으로 추가하면 protected 생성되는데 public 으로 변경하고 DiffUtil.ItemCallback 코드는 이곳에서 추가 구현해도 되고, Address_Item Class 에 추가 구현한 것을 사용해도 된다.
- rvItemList.get 대신에 getItem 으로 변경한다.
- getItemCount() 메소드는 삭제한다.
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
// RecyclerView.Adapter 대신에 ListAdapter<T, VH> 를 상속한다.
// T는 리사이클러뷰가 화면에 표시할 데이터의 타입이다.
public class AddressListAdapter extends ListAdapter<Address_Item, AddressListAdapter.ViewHolder> {
private final String TAG = this.getClass().getSimpleName();
Context context;
public AddressListAdapter(Context context, @NonNull DiffUtil.ItemCallback<Address_Item> diffCallback) {
super(diffCallback);
this.context = context;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemAddressBinding binding = ItemAddressBinding.inflate(LayoutInflater.from(parent.getContext()),parent,false);
return new ViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// 실제로 데이터를 표시하는 부분
//Address_Item currentItem = rvItemList.get(position);
Address_Item currentItem = getItem(position);
holder.bindItem(currentItem, position);
}
public class ViewHolder extends RecyclerView.ViewHolder{
ItemAddressBinding itemBinding;
public ViewHolder(@NonNull ItemAddressBinding binding) {
super(binding.getRoot());
itemBinding = binding;
}
void bindItem(Address_Item item, int position){
}
}
}
|
'안드로이드 > ListView, RecyclerView' 카테고리의 다른 글
Recyclerview with Retrofit and ListAdapter using MVVM (0) | 2022.08.28 |
---|---|
[Java] RecyclerView view binding (0) | 2022.05.23 |
[코틀린] expandable recyclerview 예제 (0) | 2021.06.03 |
RecyclerView 역순으로 리스트 출력하기 (0) | 2020.08.05 |
RecyclerView Checkbox 처리 및 Interface 처리 (0) | 2020.07.17 |