0. 구현할 기능
아래와 같은 액티비티에 RecyclerView를 사용해서 SQLite DB에 저장된 연락처 정보를 한 행씩 보여주려 한다.
activity_main.xml 코드
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="@+id/btnAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="연락처 추가"
android:textSize="28sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
1. 하나의 행을 처리할 화면 개발
먼저 리사이클러 뷰에 표시될 한 행의 화면을 처리하는 레이아웃을 만든다.
- res - layout 우클릭 - New - Layout Resource File
- 파일명을 짓고, Root element를 LinearLayout으로 바꿔 준 후 OK
개발한 contact_row.xml의 화면
contact_row.xml 코드
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="5dp"
app:cardElevation="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_weight="4"
android:orientation="vertical">
<TextView
android:id="@+id/txtName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="이름"
android:textSize="26sp" />
<TextView
android:id="@+id/txtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="전화번호"
android:textSize="26sp" />
</LinearLayout>
<ImageView
android:id="@+id/imgDelete"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_margin="10dp"
app:srcCompat="@drawable/baseline_close_24" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
2. RecyclerView Adapter 만들기
- 리사이클러 뷰는 데이터 목록을 아이템 단위의 뷰로 구성하여 화면에 표시하기 위해 어댑터를 사용한다.
순서가 약간 복잡하니 주석을 잘 보고 순서를 따라 구현한다.
ContactAdapter.java 파일
// 1. RecyclerView.Adapter를 상속 받는다.
// 2. 상속받은 클래스가 abstract 이므로, unimplemented method를 구현해야 한다.
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.reodinas2.contactapp.EditActivity;
import com.reodinas2.contactapp.MainActivity;
import com.reodinas2.contactapp.R;
import com.reodinas2.contactapp.model.Contact;
import java.io.Serializable;
import java.util.List;
// 6. extends 부분에 RecyclerView.Adapter의 데이터 타입을 적어주어야 한다.
// 우리가 만든 ViewHolder로 적는다.( <ContactAdapter.ViewHolder> )
// 7. 빨간색 에러가 뜨면,
// onCreateViewHolder, onBindViewHolder 메소드에 있는 RecyclerView.ViewHolder를
// 우리가 만든 ViewHolder로 바꿔준다.(ContactAdapter.ViewHolder)
public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ViewHolder> {
// 5. 어댑터 클래스의 멤버변수와 생성자를 만들어 준다.
Context context;
List<Contact> contactList;
// 디폴트 생성자는 만들지 않는다.
public ContactAdapter(Context context, List<Contact> contactList) {
this.context = context;
this.contactList = contactList;
}
// 8. 오버라이드 함수 3개를 전부 구현해주면 끝!
@NonNull
@Override
public ContactAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// xml 파일을 연결하는 작업
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_row, parent, false);
return new ContactAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ContactAdapter.ViewHolder holder, int position) {
// 뷰에 데이터를 셋팅한다.
Contact contact = contactList.get(position);
holder.txtName.setText(contact.name);
holder.txtPhone.setText(contact.phone);
}
@Override
public int getItemCount() {
// 전체 데이터의 갯수를 적어준다.
return contactList.size();
}
// 3. 어댑터 클래스 내에 ViewHolder 클래스를 만든다.
// 이 클래스는 contact_row.xml 화면에 있는 뷰를 연결시키는 클래스다.
// RecyclerView.ViewHolder를 상속받는다
// 4. 생성자를 만든다.
// 생성자에서, 뷰를 연결시키는 코드를 작성한다.
public class ViewHolder extends RecyclerView.ViewHolder{
TextView txtName;
TextView txtPhone;
ImageView imgDelete;
CardView cardView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
txtName = itemView.findViewById(R.id.txtName);
txtPhone = itemView.findViewById(R.id.txtPhone);
imgDelete = itemView.findViewById(R.id.imgDelete);
cardView = itemView.findViewById(R.id.cardView);
}
}
}
3. 어댑터를 사용해 데이터를 리사이클러 뷰에 표시
MainActivity.java 파일
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.reodinas2.contactapp.adapter.ContactAdapter;
import com.reodinas2.contactapp.data.DatabaseHandler;
import com.reodinas2.contactapp.model.Contact;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
Button btnAdd;
// 리사이클러 뷰를 사용할 때!
// RecyclerView, Adapter, ArrayList를 쌍으로 적어라!
RecyclerView recyclerView;
ContactAdapter adapter;
ArrayList<Contact> contactList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnAdd = findViewById(R.id.btnAdd);
// 리사이클러 뷰를 화면에 연결하고,
// 쌍으로 같이 다니는 코드도 작성
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
// 버튼을 누르면 연락처 추가 액티비티로 이동
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, AddActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onResume() {
super.onResume();
// DB로부터 데이터를 가져와서,
// 리사이클러 뷰에 표시하자.
DatabaseHandler db = new DatabaseHandler(MainActivity.this);
contactList = db.getAllContacts();
db.close();
// 어댑터를 만든다.
adapter = new ContactAdapter(MainActivity.this, contactList);
// 어댑터를 리사이클러 뷰에 셋팅!!!
recyclerView.setAdapter(adapter);
}
}
SQLite를 다루는 DatabaseHanlder 클래스와
연락처를 추가하는 AddActivity의 코드는 이전 포스팅에서 확인 할 수 있다.
https://donghyeok90.tistory.com/259
4. RecyclerView Adapter 작동 순서
1) Activity에서 Adapter 생성
// 어댑터를 만든다.
adapter = new ContactAdapter(MainActivity.this, contactList);
// 어댑터를 리사이클러 뷰에 셋팅!!!
recyclerView.setAdapter(adapter);
2) getItemCount
Adapter 생성시, 가장 먼저 호출되는 함수. 여기서는 우리가 뿌려줄 데이터의 전체 길이를 리턴한다.
만약 이를 0으로 return하면 Adapter는 보여줄 데이터가 없다고 판단한다.
그래서 데이터베이스나 List에 데이터가 있더라도 View에 표시되지 않는다.
@Override
public int getItemCount() {
// 전체 데이터의 갯수를 적어준다.
return contactList.size();
}
3) onCreateViewHolder
getItemCount 다음으로 호출되는 함수.
이름에서 알 수 있듯이 ViewHolder가 생성되는 함수로 ViewHolder 객체를 만들어준다.
@NonNull
@Override
public ContactAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// xml 파일을 연결하는 작업
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_row, parent, false);
return new ContactAdapter.ViewHolder(view);
}
4) onBindViewHolder
지금까지 생성된 ViewHolder에 데이터를 바인딩해주는 함수.
예를 들어, 데이터가 스크롤 되어서 맨 위에 있던 ViewHolder 객체가 맨 아래로 이동한다면,
그 레이아웃은 재활용하되, 데이터는 새롭게 바인딩되는 것이다.
이 때, 새로 보여질 데이터의 인덱스는 position이라는 이름으로 사용 가능하다.
즉, 아래에서 새롭게 올라오는 데이터가 리스트의 20번째 데이터라면 position은 20이 들어오게 된다.
@Override
public void onBindViewHolder(@NonNull ContactAdapter.ViewHolder holder, int position) {
// 뷰에 데이터를 셋팅한다.
Contact contact = contactList.get(position);
holder.txtName.setText(contact.name);
holder.txtPhone.setText(contact.phone);
}
5. 에뮬레이터 실행 결과
DB에 저장된 연락처들을 한 행씩 보여주는 걸 확인할 수 있다.
'Android' 카테고리의 다른 글
Android Studio - GitHub 연동하기 (0) | 2023.02.03 |
---|---|
Android Studio - RecyclerView의 아이템 클릭 이벤트 구현하기 (0) | 2023.02.01 |
Android Studio - 아이콘 이미지를 벡터 이미지로 만들기 (0) | 2023.02.01 |
Android Studio - SQLite3 데이터베이스 활용하기 (0) | 2023.01.31 |
Android Studio - 간단한 유효성 검사(이메일주소, 전화번호, 웹URL, IP주소) (0) | 2023.01.31 |