https://donghyeok90.tistory.com/261 글과 이어집니다.
0. 구현할 기능
- 리사이클러 뷰에 표시된 연락처 하나를 클릭했을 때, 그 연락처를 수정하는 액티비티로 넘어간다.
1. 연락처를 수정할 새로운 액티비티의 화면 개발
activity_edit.xml 화면
activity_edit.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=".EditActivity">
<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">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="30dp"
android:layout_marginRight="15dp"
android:gravity="center"
android:text="연락처 수정"
android:textSize="28sp" />
<EditText
android:id="@+id/editName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="50dp"
android:layout_marginRight="15dp"
android:ems="10"
android:hint="이름 입력"
android:inputType="textPersonName"
android:textSize="28sp" />
<EditText
android:id="@+id/editPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="30dp"
android:layout_marginRight="15dp"
android:ems="10"
android:hint="전화번호 입력"
android:inputType="textPersonName"
android:textSize="28sp" />
<Button
android:id="@+id/btnSave"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="50dp"
android:layout_marginRight="15dp"
android:text="수정"
android:textSize="28sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
2. 새로운 액티비티의 java 파일
EditActivity.java
public class EditActivity extends AppCompatActivity {
EditText editName;
EditText editPhone;
Button btnSave;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
editName = findViewById(R.id.editName);
editPhone = findViewById(R.id.editPhone);
btnSave = findViewById(R.id.btnSave);
3. Recycler View의 클릭 이벤트
리사이클러 뷰의 아이템을 클릭했을 때의 이벤트는 Adapter의 ViewHolder 클래스에 작성한다.
1) getAdapterPosition()
- 리사이클러 뷰에서, 몇번째 행을 눌렀는지 알 수 있는, 어댑터의 메소드
int index = getAdapterPosition();
2) 리사이클러 뷰 어댑터에서, 새로운 액티비티를 실행하는 방법
- 액티비티를 전환할 때는 intent를 사용한다.
- 그런데 어댑터는 액티비티가 아니기 때문에 인텐트에 MainActivity.this 같은 코드를 사용할 수 없다.
- 따라서 어댑터를 생성할 때 생성자로 Context 정보를 전달받는다.
// MainActivity에서 어댑터를 생성할 때 Context와 데이터를 저장할 ArrayList를 받는다
adapter = new ContactAdapter(MainActivity.this, contactList);
// 따라서 ViewHolder 에서는 Intent를 이렇게 사용한다.
Intent intent = new Intent(context, EditActivity.class);
3) 다른 액티비티로 데이터 전달 시, 클래스의 객체를 전달하는 방법
intent.putExtra("id", contact.id);
intent.putExtra("name", contact.name);
intent.putExtra("phone", contact.phone);
다른 액티비티로 데이터 전달 시, 위와 같은 코드로 객체의 멤버변수를 하나씩 전달하게 되면
요구사항이 바뀌었을 때 유지보수가 불편해진다.
따라서 객체를 통째로 전달하고, 전달받은 액티비티에서 입맛에 맞게 필요한 데이터를 뽑아갈 수 있게 하는 코드가 권장된다.
하지만 객체를 putExtra로 전달하려 하면 에러가 뜬다.
에러를 수정하려면 Serializable(직렬화) 로 캐스팅(형변환) 해줘야 한다.
intent.putExtra("contact", (Serializable) contact);
위 방법보다 더 좋은 코드는, 객체에 Serializable 인터페이스를 상속 받는다.
public class Contact implements Serializable{
public int id;
public String name;
public String phone;
이렇게 해주면 처음의 putExtra 코드에 에러가 발생하지 않는다.
intent.putExtra("contact", contact);
Serializable 해서 데이터를 보냈으면 받은 액티비티에서는 다시 클래스로 캐스팅 해줘야 한다.
Contact contact = (Contact) getIntent().getSerializableExtra("contact");
4. Adapter 전체 코드
// 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);
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 1. 인텐트에 유저가 누른 행의 이름과 전화번호를 담아서
int index = getAdapterPosition(); // 누른 행의 인덱스를 가져오는 메소드
Contact contact = contactList.get(index);
// 2. 수정하는 액티비티를 띄운다.
// 어떤 액티비티가 어떤 액티비티를 띄운다! => intent에 있어야 한다.
Intent intent = new Intent(context, EditActivity.class);
// intent.putExtra("id", contact.id);
// intent.putExtra("name", contact.name);
// intent.putExtra("phone", contact.phone);
intent.putExtra("contact", contact);
context.startActivity(intent);
}
});
}
}
}
5. 연락처 수정 액티비티 전체 코드
EditActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.reodinas2.contactapp.model.Contact;
public class EditActivity extends AppCompatActivity {
EditText editName;
EditText editPhone;
Button btnSave;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
editName = findViewById(R.id.editName);
editPhone = findViewById(R.id.editPhone);
btnSave = findViewById(R.id.btnSave);
// int id = getIntent().getIntExtra("id", 0);
// String name = getIntent().getStringExtra("name");
// String phone = getIntent().getStringExtra("phone");
//
// editName.setText(name);
// editPhone.setText(phone);
Contact contact = (Contact) getIntent().getSerializableExtra("contact");
editName.setText(contact.name);
editPhone.setText(contact.phone);
}
}
6. 에뮬레이터 실행 결과
- 연락처 하나를 클릭했을 때
- 정상적으로 화면 전환 된 것을 확인.
'Android' 카테고리의 다른 글
Android Studio - EditText 입력 이벤트 처리 (addTextChangedListener) (0) | 2023.02.03 |
---|---|
Android Studio - GitHub 연동하기 (0) | 2023.02.03 |
Android Studio - RecyclerView와 Adapter를 이용하여 리스트를 화면에 표시하기 (1) | 2023.02.01 |
Android Studio - 아이콘 이미지를 벡터 이미지로 만들기 (0) | 2023.02.01 |
Android Studio - SQLite3 데이터베이스 활용하기 (0) | 2023.01.31 |