기존 포스팅에서는 뷰홀더와 어댑터를 한 파일에서 처리했었다.
itstudy-mary.tistory.com/209?category=929375
그런데, 이제 배우고 공부하고 하다 보니까 어댑터와 뷰홀더를 따로 처리하는 방식이 있었다(!)
당연하게도 장단점이 존재하는데,
장점
- 같은 리사이클되는 뷰의 형태를 가지며(그러니까, 같은 뷰홀더를 쓸 수 있는 상태를 말한다.), 다른 데이터를 넣어야 할 때 어댑터만 다르게 유지하고 뷰홀더는 같은 것을 사용해도 무방하다.
- 따라서 코드의 모듈화가 쉬워지고, (개인적이지만) 코드의 가독성이 올라간다.
단점
- 설계를 잘못하다가는 코드의 결합도가 올라갈 가능성이 있다.
개인적으로는 뷰홀더를 따로 두는 것이 참 편했기 때문에.. 예시는 어제 끝낸(어차피 인텐트랑 퍼미션 공부용이라 따로 디자인은 안할거임..!) HYPersonnalApp를 기준으로 한다.
itstudy-mary.tistory.com/250?category=952417
보다시피 두 개를 다른 파일로 생성했다.
처음 만들어야 할 것은 어댑터이다. 어댑터를 이용해 부모 뷰에 있는 리사이클러뷰와 뷰홀더를 결합한다.
그러니, 어댑터를 만들기 전 부모 뷰(이 프로젝트에선 액티비티임)에서 리사이클러뷰를 찾아주어야 한다.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_book_number);
findView();
init();
setListener();
readPhoneContact();
}
private void findView(){
...
recyclerView = findViewById(R.id.recyclerview);
...
}
이제 어댑터를 만든다.
RecyclerView.Adapter를 상속받으면, 리사이클러뷰의 어댑터 역할로서 어떤 메소드를 사용해야하는지 친절하게 알려준다(프레임워크의 특장점!).
- Adapter
package com.example.hypersonnalsnsapp.selectBookNumber.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.hypersonnalsnsapp.R;
import com.example.hypersonnalsnsapp.selectBookNumber.model.PhoneBook;
import com.example.hypersonnalsnsapp.selectSMSNumber.adapter.SelectSMSViewHolder;
import com.example.hypersonnalsnsapp.util.DebugLogUtil;
import java.util.ArrayList;
import java.util.List;
public class SelectBookNumberAdapter extends RecyclerView.Adapter {
private static final String TAG = "SelectBookNumberAdapter";
private List<PhoneBook> phoneBookList = new ArrayList<>();
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_holder_phone_contact_list, parent, false);
return new SelectBookNumberViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
SelectBookNumberViewHolder selectBookNumberViewHolder = (SelectBookNumberViewHolder) holder;
selectBookNumberViewHolder.phoneBook=phoneBookList.get(position);
selectBookNumberViewHolder.updateView();
}
public void reload(List<PhoneBook> phoneBookList){
this.phoneBookList.clear();
this.phoneBookList.addAll(phoneBookList);
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return phoneBookList.size();
}
}
onCreateViewHolder. 이 함수에서 먼저 데이터가 들어갈 껍데기를 생성한다고 보면 될 것 같다.
이후 onBindViewHolder 함수에서 이 생성된 껍데기에 포지션에 따라 데이터를 넣어준다고 생각하면 될 것 같다.
그러니, 리사이클러뷰가 얼마나 껍데기를 생성해야할지 그것도 알려주어야 하는데, 이것은 getItemCount()메서드에서 데이터의 전체적인 크기를 리턴 받아야 한다.
(이 프로젝트에서는 휴대폰 연락처를 cursor을 이용해서 받아오기 때문에 그 데이터를 while문을 통해 이미 앞서 ArrayList에 담아둔 상태입니다.)
액티비티입니다. 다음과 같이 데이터를 미리 받아서, 어댑터의 reload 매서드를 통해 미리 ArrayList를 만들어두었죠.
public void readPhoneContact(){
List<PhoneBook> phoneBookList = new ArrayList<>();
ContentResolver resolver=SelectBookNumberActivity.this.getContentResolver();
Uri phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = {ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER};
Cursor c= resolver.query(phoneUri, projection, null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
while (c.moveToNext()){
String id = c.getString(c.getColumnIndex(projection[0]));
String name = c.getString(c.getColumnIndex(projection[1]));
String number = c.getString(c.getColumnIndex(projection[2]));
PhoneBook phoneBook = new PhoneBook();
phoneBook.setId(id);
phoneBook.setName(name);
phoneBook.setPhoneNumber(number);
DebugLogUtil.logD(TAG, phoneBook.getPhoneNumber());
phoneBookList.add(phoneBook);
}
selectBookNumberAdapter.reload(phoneBookList);
}
아직 바인딩할 홀더가 없으니 이 파일을 완성할 수 없습니다.
이제 바인딩할 뷰홀더를 만들어줍니다. 마찬가지로 RecyclerView.ViewHolder만 상속받으면 됩니다.
- ViewHolder
package com.example.hypersonnalsnsapp.selectBookNumber.adapter;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.hypersonnalsnsapp.R;
import com.example.hypersonnalsnsapp.getBankAndAddress.GetBankAndAddressActivity;
import com.example.hypersonnalsnsapp.selectBookNumber.model.PhoneBook;
import com.example.hypersonnalsnsapp.selectProduct.SelectProductActivity;
import com.example.hypersonnalsnsapp.util.ActivityUtil;
import com.example.hypersonnalsnsapp.util.DebugLogUtil;
import com.example.hypersonnalsnsapp.util.SharedPreferenceUtil;
public class SelectBookNumberViewHolder extends RecyclerView.ViewHolder {
private static final String TAG = "SelectBookNumberViewHol";
private TextView textViewName;
private TextView textViewPhoneNumber;
private TextView textViewSelect;
public PhoneBook phoneBook;
public SelectBookNumberViewHolder(@NonNull View itemView) {
super(itemView);
findView();
setListener();
}
private void findView() {
textViewName = itemView.findViewById(R.id.textViewName);
textViewPhoneNumber = itemView.findViewById(R.id.textViewPhoneNumber);
textViewSelect = itemView.findViewById(R.id.textViewSelect);
}
private void setListener() {
textViewSelect.setOnClickListener(v -> {
...
}
public void updateView() {
textViewName.setText(phoneBook.getName());
String phoneNum = phoneBook.getPhoneNumber();
if (!phoneNum.contains("-")) {
if (phoneNum.length() == 10) {
String address1 = phoneNum.substring(0, 3);
String address2 = phoneNum.substring(3, 6);
String address3 = phoneNum.substring(6, 10);
textViewPhoneNumber.setText(address1 + "-" + address2 + "-" + address3);
} else if (phoneNum.length() == 11) {
String address1 = phoneNum.substring(0, 3);
String address2 = phoneNum.substring(3, 7);
String address3 = phoneNum.substring(7, 11);
textViewPhoneNumber.setText(address1 + "-" + address2 + "-" + address3);
}
} else {
textViewPhoneNumber.setText(phoneNum);
}
}
}
여기는 사실상.. 할 일이 없고요... 뷰홀더 내부클래스만 선언해주고, 리사이클러뷰 각각의 아이템에서 무엇을 해줄지만 결정해주면 됩니다. 보시다시피 어댑터의 onBind에서 넘어오는 데이터를 view에 set하거나, 리스너를 여기에 걸 수 있죠. 아주 편안합니다.
이제 createViewHolder 매서드에서 만든 뷰홀더로 뷰를 지정해주고, onBindViewHolder 포지션마다 데이터를 삽입하기만 하면 끝납니다..
마지막으로 부모 뷰(액티비티)로 돌아와서 어댑터를 선언해주고, 리사이클러뷰에 어댑터를 set 하면 정말 끝납니다.
private void init(){
selectBookNumberAdapter = new SelectBookNumberAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(SelectBookNumberActivity.this));
recyclerView.setAdapter(selectBookNumberAdapter);
}
아주.. 편안해요. 어댑터와 함께 처리하는 것도 좋지만 이렇게 따로 사용해보는것도 추천드립니다.
추신 :
가급적 뷰홀더의 리스너에서는 외부서버나 데이터베이스에서 데이터를 가지고 오는 것을 추천드리진 않습니다. 뷰홀더에겐 뷰만 맡기는 것이 좋아요. 데이터 처리는 액티비티쪽에서 해주세요. 까딱하다간 포지션 오류가 일어날 수 있고, 그것으로 인해 서버에 부하가 걸릴 수 있으니..
꼭.. 꼭 포지션이 필요하다면 부모뷰 쪽에서 public으로 빈 컨테이너를 선언하고, 부모뷰에서 setPosition 함수와 이후의 데이터 호출 매서드를 하나 더 생성한 후 이벤트 리스너로 setPosition과 데이터 매서드를 호출하는 형태를 추천드립니다..
'Android' 카테고리의 다른 글
Android Studio, JAVA] 컬러 그래디언트 만들기 (0) | 2020.11.25 |
---|---|
Android Studio, JAVA ] sphere Panorama view (0) | 2020.11.20 |
[Android Studio, Java] (간단하게) SharedPreferenced가 무엇일까? (0) | 2020.10.20 |
Android Studio, JAVA] AIDL 서비스 바인딩 (0) | 2020.08.18 |
Android Studio, JAVA] 파이어베이스 등록하기 (0) | 2020.08.13 |