Imgur: The magic of the Internet
토글버튼을 클릭시 리사이클러뷰 아이템에 표현된 단위를 한번에 모두 바꾸고 싶은데, 실패하고
고민하다 질문드립니다. 현 상황에 대한 이미지는 링크를 봐주세요.
링크의 이미지에서는 토글버튼을 클릭시 모두 변하는게 아니라 다음 추가되는 아이템에만 적용되어 변합니다.
리사이클러뷰를 사용하고 있고 어댑터는 ListAdapter를 사용하였고 DiffUtil을 함께 사용했습니다.
이 문제를 해결하기위해 제가 하려고 했던것
1. 단위는 모든 아이템이 공통적으로 가지는 것이고 한번에 바뀌는 것을 원하기에 단위에 해당하는 변수를
static으로 선언하고 바인딩하고 업데이트 하면되겠다.
-> 그럴듯 했으나 실패. 처음에는 원인을 몰랐는데 알아보니 static이 클래스에 속하는 변수라 static으로 변
하는 값을 DiffUtill에서는 인지하지 못합니다. 왜냐하면 인스턴스 필드가 아니기때문이죠.
링크의 이미지가 static으로 구현했을때인데 값은 변해서 어댑터에서 바인딩하기때문에
하나씩은 바뀌긴했습니다.
2. 토글버튼 클릭시 모든 리스트들을 불러와서 하나하나 필드의 값을 변경된 토글값으로 셋후에 submitList()에 업데이트시켜주기.
사실 이 방법은 하나하나 리스트들을 불러와서 for문으로 일일이 필드값을 새로 셋팅해줘야하기에
썩 마음에 드는 방법은 아니었지만 제 수준에서는 이것밖에 생각안나서 시도했습니다.
될줄알았는데 계속안되길래 원인을 한참찾다가, DiffUtil에서 값을 비교하는 것이 잘못됐나 싶어서
이것저것 바꾸다가 생각난것이..
토글버튼 클릭했을때 리스트들을 하나하나 불러와서 필드값을 변경했다 했는데, 그 필드가 String 타입이었
으므로 값을 리턴할때 주소를 리턴하게 되는것이고 결국 값을 바꾸면 oldItem의 값도 같이 바뀌어서
DiffUtil에서 oldItem과 newItem을 비교했을때 결국 동일한 아이템취급을 받았던것 같습니다.
그래서 업데이트가 일어나지 않았구요..
대충이정도인데 문제는 여기서 어떻게 해결하면 좋을지 모르겠습니다.
리스트를 새로 하나만들고 아이템도 하나하나 새로만들어 값을 세팅하고 리스트에 넣어 업데이트하면
완전 다른 아이템이라 업데이트 될것이라고 예상은 되지만 이렇게 새로 하나하나 다시 만드는게
너무 비효율적이라 생각됩니다.. 조언좀 해주시면 감사하겠습니다.
Activity.java
///// 토글버튼 클릭
@Override
public void onUnitBtnClicked(int curRoutinePos, String unit) {
Object obj = listAdapter.getRoutineItem(curRoutinePos);
RoutineModel item = (RoutineModel) obj;
if(obj instanceof RoutineModel) {
// 리스트 하나하나 unit 변경하기
for(RoutineDetailModel detailItem : item.getDetailItemList()) {
detailItem.setUnit(unit);
}
listAdapter.submitList(getUpdatedList());
}
}
// 리스트 업데이트
private List<Object> getUpdatedList() {
List<Object> mixedList = new ArrayList<>();
for(RoutineModel rm: items){
mixedList.add(rm);
if(rm.getDetailItemList() != null && rm.getDetailItemSize() > 0){
for(RoutineDetailModel rmdetilas: rm.getDetailItemList()){
mixedList.add(rmdetilas);
}
}
}
return mixedList;
}
RoutineDetailModel.java
public class RoutineDetailModel {
public int id;
private int set = 1;
private String weight;
private String reps;
public String unit = "kg";
public RoutineDetailModel() {
Random random = new Random();
this.id = random.nextInt();
}
public RoutineDetailModel(int set) {
Random random = new Random();
this.id = random.nextInt();
this.set = set+1;
}
public int getSet() {
return set;
}
public int getId() {
return id;
}
public void setUnit(String unit) {
this.unit = unit;
}
public String getUnit() {
return unit;
}
@Override
public int hashCode() {
return Objects.hash(set, weight);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
RoutineDetailModel that = (RoutineDetailModel) obj;
return Objects.equals(this.set, that.set) && Objects.equals(this.unit, that.unit);
}
}
DiffUtil.java
public class RoutineDiffUtil2 extends DiffUtil.ItemCallback<Object> {
// 여기서는 아이템을 구분하는 고유한 값으로 비교하기
@Override
public boolean areItemsTheSame(@NonNull Object oldItem, @NonNull Object newItem) {
if (oldItem instanceof RoutineModel && newItem instanceof RoutineModel) {
return ((RoutineModel) oldItem).id == ((RoutineModel) newItem).id;
}
else if (oldItem instanceof RoutineDetailModel && newItem instanceof RoutineDetailModel) {
return ((RoutineDetailModel) oldItem).id == ((RoutineDetailModel) newItem).id;
}
else if(oldItem instanceof RoutineModel && newItem instanceof RoutineDetailModel) {
// Routine모델에서 Detail을 꺼내와서 newObj랑 비교해야하나?
return false;
}
else {
return false;
}
}
// 아이템이 가지고 있는 데이터까지 비교하기
@SuppressLint("DiffUtilEquals")
@Override
public boolean areContentsTheSame(@NonNull Object oldItem, @NonNull Object newItem) {
return oldItem.equals(newItem);
}
}