Android 개발 의 DiffUtil 사용 에 대한 자세 한 설명
DiffUtil 은 집합 변 화 를 찾 는 도구 류 로 RecyclerView 와 함께 사용 합 니 다.RecyclerView 에 대해 잘 모 르 면 자 료 를 읽 을 수 있 습 니 다.여 기 는 소개 하지 않 겠 습 니 다.
효과 그림 먼저 넣 기:
우리 가 버튼 을 눌 렀 을 때 이 RecyclerView 가 보 여 준 집합 이 바 뀌 었 고,어떤 요 소 는 추가 되 었 다(8.Jason),어떤 요 소 는 이동 되 었 다(3.Rose),심지어 수정 되 었 다(2.Fndroid).
RecyclerView 는 각 항목 의 애니메이션 을 다른 방식 으로 새로 고 칩 니 다.
notifyItemInserted
notifyItemChanged
notifyItemMoved
notifyItemRemoved
연속 적 인 몇 개의 Item 리 셋 에 대해 서 는 다음 과 같이 호출 할 수 있 습 니 다.
notifyItemRangeChanged
notifyItemRangeInserted
notifyItemRangeRemoved
한편,집합 이 변화 할 때
notifyDataSetChanged
방법 으로 전체 인터페이스의 갱신 만 할 수 있 고 집합 변화 에 따라 모든 변화 요소 에 애니메이션 을 추가 할 수 없다.그래서 이 문 제 를 해결 하기 위해 DiffUtil 이 생 겼 습 니 다.DiffUtil 의 역할 은 집합 중의 모든 Item 에 발생 하 는 변 화 를 찾아내 고 모든 변화 에 대응 하 는 갱신 을 하 는 것 이다.
이 DiffUtil 은 Eugene Myers 의 차별 화 된 알고리즘 을 사용 합 니 다.이 알고리즘 자 체 는 요소 의 이동 을 검사 할 수 없습니다.즉,이동 은 먼저 삭제 하고 다시 증가 하 는 것 으로 간주 되 고 DiffUtil 은 알고리즘 결과 후에 이동 검 사 를 한 번 합 니 다.원소 의 이동 을 감지 하지 않 은 상태 에서 알고리즘 의 시간 복잡 도 는 O(N+D2)이 고 원소 의 이동 을 감지 하면 복잡 도 는 O(N2)라 고 가정 한다.따라서 집합 자체 가 순서 가 정 해 져 있 으 면 이동 검 사 를 하지 않 고 효율 을 높 일 수 있다.
다음은 우리 함께 이 공 구 를 어떻게 사용 하 는 지 보 자.
우선 각 Item 에 대해 데 이 터 는 Student 대상 입 니 다.
class Student {
private String name;
private int num;
public Student(String name, int num) {
this.name = name;
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
이어서 레이아웃(생략)과 어댑터 를 정의 합 니 다.
class MyAdapter extends RecyclerView.Adapter {
private ArrayList<Student> data;
ArrayList<Student> getData() {
return data;
}
void setData(ArrayList<Student> data) {
this.data = new ArrayList<>(data);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(RecyclerViewActivity.this).inflate(R.layout.itemview, null);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
MyViewHolder myViewHolder = (MyViewHolder) holder;
Student student = data.get(position);
myViewHolder.tv.setText(student.getNum() + "." + student.getName());
}
@Override
public int getItemCount() {
return data.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv;
MyViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.item_tv);
}
}
}
데이터 집합 초기 화:
private void initData() {
students = new ArrayList<>();
Student s1 = new Student("John", 1);
Student s2 = new Student("Curry", 2);
Student s3 = new Student("Rose", 3);
Student s4 = new Student("Dante", 4);
Student s5 = new Student("Lunar", 5);
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
students.add(s5);
}
이어서 어댑터 를 실례 화하 고 RecyclerView 에 설정 합 니 다.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_view);
initData();
recyclerView = (RecyclerView) findViewById(R.id.rv);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyAdapter();
adapter.setData(students);
recyclerView.setAdapter(adapter);
}
이 내용 들 은 모두 이 편의 내용 이 아니 지만 주의해 야 할 부분 은 Adapter 의 정의 입 니 다.
class MyAdapter extends RecyclerView.Adapter {
private ArrayList<Student> data;
ArrayList<Student> getData() {
return data;
}
void setData(ArrayList<Student> data) {
this.data = new ArrayList<>(data);
}
//
......
}
여기setData
방법 은 Array List 의 인용 을 직접 저장 하 는 것 이 아니 라 Array List 를 다시 만 드 는 것 입 니 다.먼저 기억 하고 나중에 왜 이렇게 해 야 하 는 지 설명 합 니 다.DiffUtil 의 사용 방법:
마 우 스 를 눌 렀 을 때 Array List 의 내용 을 수정 합 니 다.
public void change(View view) {
students.set(1, new Student("Fndroid", 2));
students.add(new Student("Jason", 8));
Student s2 = students.get(2);
students.remove(2);
students.add(s2);
ArrayList<Student> old_students = adapter.getData();
DiffUtil.DiffResult result = DiffUtil.calculateDiff(new MyCallback(old_students, students), true);
adapter.setData(students);
result.dispatchUpdatesTo(adapter);
}
2-6 줄 은 집합 을 수정 하고 8 줄 은 adapter 의 집합 을 오래된 데이터 로 가 져 옵 니 다.9 번 째 줄 호출
DiffUtil.calculateDiff
방법 으로 집합 차 이 를 계산 하 는 데 중심 을 두 어야 합 니 다.여 기 는 CallBack 인터페이스의 실현 류(계산 규칙 을 지정 하 는 데 사용)를 전송 하고 새로운 데 이 터 를 이 인터페이스의 실현 류 에 전달 해 야 합 니 다.마지막 으로 boolean 유형의 매개 변수 가 있 습 니 다.이 매개 변 수 는 Move 검 사 를 해 야 하 는 지 여 부 를 지정 합 니 다.필요 하지 않 으 면 Item 이 이동 하면...먼저 remove 하고 insert 로 여 겨 집 니 다.트 루 로 지정 되 어 움 직 이 는 그림 의 이동 효과 가 있 습 니 다.열 번 째 줄 은 Adapter 에 새로운 데 이 터 를 다시 설정 합 니 다.
11 번 째 줄 에서 9 번 째 줄 에서 받 은 DiffResult 대상
dispatchUpdatesTo
을 호출 하 는 방법 은 RecyclerView 에 변 화 된 아 이 템 을 새로 고침 하 라 고 알 립 니 다.여기 서 위 에서 말 한
setData
방법 으로 돌아 갑 니 다.우 리 는 여기 서 두 개의 집합 을 구분 해 야 하기 때문에setData
방법 에서 인용 을 직접 저장 하면 2-6 줄 의 수정 은 Adapter 의 집합(자바 지식)을 직접 수정 합 니 다.아 이 템 의 이동 을 검사 하지 않 으 면 다음 과 같이 효과 가 있 습 니 다.
이어서 CallBack 인터페이스의 실현 클래스 가 어떻게 정의 되 는 지 봅 시다.
private class MyCallback extends DiffUtil.Callback {
private ArrayList<Student> old_students, new_students;
MyCallback(ArrayList<Student> data, ArrayList<Student> students) {
this.old_students = data;
this.new_students = students;
}
@Override
public int getOldListSize() {
return old_students.size();
}
@Override
public int getNewListSize() {
return new_students.size();
}
// Item
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return old_students.get(oldItemPosition).getNum() == new_students.get(newItemPosition).getNum();
}
// Item , Item
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return old_students.get(oldItemPosition).getName().equals(new_students.get(newItemPosition).getName());
}
}
여 기 는 학 번 에 따라 같은 아 이 템 여 부 를 판단 하고 이름 에 따라 이 아 이 템 이 수정 되 었 는 지 여 부 를 판단 합 니 다.실제로 이 Callback 추상 류 는 또 하나의 방법
getChangePayload()
이 있다.이 방법의 역할 은 우리 가 이 방법 을 통 해 Adapter 에 게 이 Item 에 대해 전체 업데이트 가 아니 라 부분 적 인 업 데 이 트 를 할 수 있다 는 것 을 알려 주 는 것 이다.이 페 이 로드 가 뭔 지 알 아야 돼 요?payload 는 Item 의 변 화 를 묘사 하 는 대상 입 니 다.즉,우리 의 Item 에 어떤 변화 가 생 겼 는 지,이러한 변 화 는 하나의 payload 로 봉 인 됩 니 다.그래서 우 리 는 보통 Bundle 로 충당 할 수 있 습 니 다.
이 어
getChangePayload()
방법 은areItemsTheSame()
true 로 돌아 가 고areContentsTheSame()
false 로 돌아 갈 때 리 셋 된 것 이다.즉,하나의 Item 의 내용 에 변화 가 생 겼 는데 이 변 화 는 부분 적 인 것 일 수 있다(예 를 들 어 웨 이 보 의'좋아요',우 리 는 전체 Item 이 아 닌 아이콘 만 새로 고침 해 야 한다).그래서getChangePayload()
에 Object 를 패키지 하여 RecyclerView 에 부분 적 인 리 셋 을 알려 줄 수 있 습 니 다.만약 에 상기 중학교 번호 와 이름 이 서로 다른 TextView 로 표시 된다 고 가정 하면 우리 가 한 학 번 에 해당 하 는 이름 을 수정 할 때 부분 적 으로 이름 을 바 꾸 면 된다(여기 서 예 는 비교적 불필요 해 보일 수 있 지만 하나의 Item 이 복잡 하면 쓸모 가 비교적 크다).
먼저 Callback 의 이 방법 을 다시 쓰 는 것 입 니 다.
@Nullable
@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
Student newStudent = newStudents.get(newItemPosition);
Bundle diffBundle = new Bundle();
diffBundle.putString(NAME_KEY, newStudent.getName());
return diffBundle;
}
돌아 온 이 상 대 는 어디서 받 을 수 있 을까요?실제로RecyclerView.Adapter
에서 두 가지onBindViewHolder
방법 이 있 습 니 다.하 나 는 우리 가 다시 써 야 하 는 것 이 고 다른 세 번 째 매개 변 수 는 바로 payload 의 목록 입 니 다.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads) {}
따라서 우 리 는 Adapter 에서 이 방법 을 다시 쓰기 만 하면 됩 니 다.List 가 비어 있 으 면 원래 의 onBindViewHolder 를 실행 하여 전체 Item 의 업 데 이 트 를 진행 합 니 다.그렇지 않 으 면 paylods 의 내용 에 따라 부분 적 인 리 셋 을 진행 합 니 다.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
} else {
MyViewHolder myViewHolder = (MyViewHolder) holder;
Bundle bundle = (Bundle) payloads.get(0);
if (bundle.getString(NAME_KEY) != null) {
myViewHolder.name.setText(bundle.getString(NAME_KEY));
myViewHolder.name.setTextColor(Color.BLUE);
}
}
}
이곳 의 pay loads 는 null 이 되 지 않 기 때문에 빈 것 인지 아 닌 지 를 직접 판단 하면 됩 니 다.여기 주의:RecyclerView 에 대량의 데 이 터 를 불 러 오 면 알고리즘 이 바로 완성 되 지 않 을 수 있 습 니 다.ANR 의 문제 에 주의 하고 단독 스 레 드 를 열 어 계산 할 수 있 습 니 다.
총결산
Android 에서 DiffUtil 의 사용 은 여기까지 소개 되 었 습 니 다.이 글 이 Android 개발 자 들 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 댓 글 을 남 겨 주 십시오.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.