728x90

코틀린 기반으로 코드를 구현하면 쉽게 샘플 예제를 찾을 수 있다. 하지만 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){
        }
    }
 
}
 

 

 

 

블로그 이미지

Link2Me

,