-리스트뷰의 단점은 각 목록(아이템)을 파괴하고 생성하기 때문에 메모리를 효율이 안 좋습니다.
이 단점을 보안해서 리사이클러뷰가 만들어 졌습니다. 아이템을 재활용해서 메모리 효율을 개선했습니다. 에스스컬레이터로 예를 들어 보겠습니다.. 에스컬레이터(리사이클러뷰)에 타는 사람들(데이터)은 다르지만 에스컬레이터의 발판은 계속 움직이면서 다른 사람들을 태웁니다.
-ViewHolder 패턴의 강제성 차이.
리사이클러뷰를 사용해서 간단한 전화번호부 앱을 만들겠습니다. 이름과 전화번호를 입력받아 리사이클러뷰의 목록에 띄우는 기능을 구현하겠습니다.
1.레이아웃
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/edit_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="이름을 입력해주세요."/>
<EditText
android:id="@+id/edit_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="핸드폰 번호를 입력해주세요"/>
<Button
android:id="@+id/btn_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="저장"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.appcompat.widget.LinearLayoutCompat>
2.아이템뷰
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="이름"
android:textSize="30sp"
android:textColor="@color/black"/>
<TextView
android:id="@+id/tv_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="전화번호"
android:textColor="@color/black"
android:textSize="20sp"/>
</androidx.appcompat.widget.LinearLayoutCompat>
3.데이터클래스
-리사이클러뷰에 데이터들을 담을 데이터 클래스.
public class Data {
private String name;
private String number;
public Data(String name, String number) {
this.name =name;
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
4.어댑터
-어댑터는 하나의 객체로서, 보여지는 View와 그 View에 올릴 Data를 연결하는
일종의 다리다. 즉 데이터의 원본을 받아 관리하고, 어댑터뷰가 출력할 수 있는 형태로 데이터를 제공하는 중간 객체 역할을 한다.
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
private String TAG = "Adapter";
private Context mContext;
private ArrayList<Data> mArrayList; //데이터를 담을 어레이리스트
public Adapter(Context context, ArrayList<Data> arrayList) {
this.mArrayList = arrayList;
this.mContext =context;
}
//리스트의 각 항목을 이루는 디자인(xml)을 적용.
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService (Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate (R.layout.item, parent, false);
ViewHolder vh = new ViewHolder (view);
return vh;
}
//리스트의 각 항목에 들어갈 데이터를 지정.
@Override
public void onBindViewHolder(@NonNull Adapter.ViewHolder holder, int position) {
Data data = mArrayList.get (position);
holder.tv_name.setText (data.getName ());
holder.tv_number.setText (data.getNumber ());
}
//화면에 보여줄 데이터의 갯수를 반환.
@Override
public int getItemCount() {
Log.d (TAG, "getItemCount: "+mArrayList.size ());
return mArrayList.size ();
}
//뷰홀더 객체에 저장되어 화면에 표시되고, 필요에 따라 생성 또는 재활용 된다.
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tv_name, tv_number;
public ViewHolder(@NonNull View itemView) {
super (itemView);
this.tv_name = itemView.findViewById (R.id.tv_name);
this.tv_number = itemView.findViewById (R.id.tv_number);
}
}
}
5.메인액티비티
public class MainActivity extends AppCompatActivity {
private Context mContext;
private ArrayList<Data> mArrayList;
private Adapter mAdapter;
private RecyclerView mRecyclerView;
private EditText edit_name, edit_number;
private Button btn_save;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
mContext = getApplicationContext ();
edit_name = findViewById (R.id.edit_name);
edit_number = findViewById (R.id.edit_number);
btn_save = findViewById (R.id.btn_save);
mRecyclerView = findViewById (R.id.recycler);
//레이아웃메니저는 리사이클러뷰의 항목 배치를 어떻게 할지 정하고, 스크롤 동작도 정의한다.
//수평/수직 리스트 LinearLayoutManager
//그리드 리스트 GridLayoutManager
LinearLayoutManager layoutManager = new LinearLayoutManager (mContext, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager (layoutManager);
mArrayList = new ArrayList<> ();
mAdapter = new Adapter (mContext, mArrayList);
mRecyclerView.setAdapter (mAdapter);
//버튼 클릭이벤트
//이름과 전화번호를 입력한 후 버튼을 클릭하면 어레이리스트에 데이터를 담고 리사이클러뷰에 띄운다.
btn_save.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View view) {
if(edit_name.getText ().length ()==0&&edit_number.getText ().length ()==0){
Toast.makeText (mContext,"이름과 전화번호를 입력해주세요", Toast.LENGTH_SHORT).show ();
}else{
String name = edit_name.getText ().toString ();
String number = edit_number.getText ().toString ();
edit_name.setText ("");
edit_number.setText ("");
Data data = new Data (name, number);
mArrayList.add (data);
mAdapter.notifyItemInserted (mArrayList.size ()-1);
}
}
});
}
}
6.결과
다음 포스팅은 리사이클러뷰의 아이템들을 클릭, 수정, 삭제 기능을 추가 해보겠습니다.
메인엑티비티에 Data data = new Data(name, number); 여기서 name, number에 빨간줄이 쳐지네요... 어떻게 해결할수 있을까요?