app / res / layout / activity_main.xml
app / res / layout / contact_row.xml
app / res / layout / activity_add.xml
app / res / layout / activity_update.xml
app / java / com.bpdev.contacts / MainActivity.java
app / java / com.bpdev.contacts / adapter / ContactAdapter.java
app / java / com.bpdev.contacts / model / Contact.java
app / java / com.bpdev.contacts / data / DatabaseHandler.java
app / java / com.bpdev.contacts / AddActivity.java
app / java / com.bpdev.contacts / UpdateActivity.java
app / res / layout / 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:layout_margin="10dp"
android:padding="10dp"
android:text="연락처 추가하기"
android:textSize="24sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:background="#3F51B5" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
app / res / layout / 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:cardBackgroundColor="#D5D6D6">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="5"
android:orientation="vertical">
<TextView
android:id="@+id/txtName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="이름"
android:textSize="24sp" />
<TextView
android:id="@+id/txtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginStart="11dp"
android:layout_marginTop="10dp"
android:text="전화번호"
android:textSize="24sp" />
</LinearLayout>
<ImageView
android:id="@+id/imgDelete"
android:layout_width="40dp"
android:layout_height="40dp"
app:srcCompat="@drawable/baseline_clear_24" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
app / res / layout / activity_add.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=".AddActivity">
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginTop="100dp"
android:layout_marginEnd="100dp"
android:gravity="center|top"
android:text="연락처 추가"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/editName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginTop="67dp"
android:layout_marginEnd="100dp"
android:ems="10"
android:hint="이름"
android:inputType="text"
android:textColorHint="#DDDDDD"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<EditText
android:id="@+id/editPhone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="100dp"
android:ems="10"
android:hint="전화번호"
android:inputType="number"
android:textColorHint="#DDDDDD"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/editName" />
<Button
android:id="@+id/btnSave"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="150dp"
android:layout_marginTop="120dp"
android:layout_marginEnd="150dp"
android:padding="10dp"
android:text="저장"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/editPhone" />
</androidx.constraintlayout.widget.ConstraintLayout>
app / res / layout / activity_update.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=".UpdateActivity">
<Button
android:id="@+id/btnSave"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="131dp"
android:layout_marginTop="119dp"
android:layout_marginEnd="130dp"
android:padding="10dp"
android:text="저장"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/editPhone" />
<EditText
android:id="@+id/editPhone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="88dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="87dp"
android:ems="10"
android:hint="전화번호"
android:inputType="number"
android:textColorHint="#DDDDDD"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/editName" />
<EditText
android:id="@+id/editName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="88dp"
android:layout_marginTop="67dp"
android:layout_marginEnd="87dp"
android:ems="10"
android:hint="이름"
android:inputType="text"
android:textColorHint="#DDDDDD"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginTop="100dp"
android:layout_marginEnd="100dp"
android:gravity="center|top"
android:text="연락처 수정"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
app / java / com.bpdev.contacts / MainActivity.java
package com.bpdev.contacts;
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.bpdev.contacts.adapter.ContactAdapter;
import com.bpdev.contacts.data.DatabaseHandler;
import com.bpdev.contacts.model.Contact;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
Button btnAdd;
// adapter 3개 한세트
RecyclerView recyclerView;
ContactAdapter adapter;
ArrayList<Contact> contactArrayList = new ArrayList<>();
@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);
}
});
// 여기 있던 코드 네 줄 onResume으로 옮김
}
@Override
protected void onResume() {
super.onResume();
// 데이터를 먼저 불러오고, contactArrayList에 저장해야 한다.
// DB에서 데이터를 가져온다.
DatabaseHandler handler = new DatabaseHandler(MainActivity.this, "contact_db", null, 1);
contactArrayList = handler.getAllContacts(); // 가져와서 보여주기 위해 메모리에 저장
adapter = new ContactAdapter(MainActivity.this, contactArrayList);
recyclerView.setAdapter(adapter);
}
}
app / java / com.bpdev.contacts / adapter / ContactAdapter.java
package com.bpdev.contacts.adapter;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
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.bpdev.contacts.R;
import com.bpdev.contacts.UpdateActivity;
import com.bpdev.contacts.data.DatabaseHandler;
import com.bpdev.contacts.model.Contact;
import java.util.ArrayList;
public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ViewHolder> {
Context context; // alert Dialog
ArrayList<Contact> contactArrayList; // 메인에서 만들어서 알려줄거임
public ContactAdapter(Context context, ArrayList<Contact> contactArrayList) {
this.context = context;
this.contactArrayList = contactArrayList;
}
@NonNull
@Override
public ContactAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_row, parent, false);
return new ContactAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Contact contact = contactArrayList.get(position); // 안드로이드 프레임워크가 일 작동 모듈을 다 만들어 두었어. // 여기 좀 문제인 것 같다 todo
holder.txtName.setText(contact.name);
holder.txtPhone.setText(contact.phone);
}
@Override
public int getItemCount() {
return contactArrayList.size();
}
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);
imgDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showAlertDialog();
}
});
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// UpdateActivity를 실행하는 코드를 여기에 작성
Intent intent = new Intent(context, UpdateActivity.class);
int index = getAdapterPosition();
Contact contact = contactArrayList.get(index);
intent.putExtra("contact", contact); // Contact 클래스에 implements Serializable 추가 // 중요 실무 팁
// intent.putExtra("id", contact.id);
// intent.putExtra("name", contact.name);
// intent.putExtra("phone", contact.phone);
context.startActivity(intent); // 상속받아서 사용가능한 함수
}
});
}
private void showAlertDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("주소록 삭제");
builder.setMessage("정말 삭제하시겠습니까?");
builder.setCancelable(false);
// Yes 버튼 누르면 동작하라~
builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// contactArrayList 안에 있는 인덱스에 해당하는 데이터를 사용하면 된다.
// 상속받은 함수 이용: 유저가 누른 인덱스를 가져올 수 있는 함수.
int index = getAdapterPosition();
// DB에서 삭제해야 완전히 삭제된 거죠
DatabaseHandler handler = new DatabaseHandler(context, "contact_db", null, 1); // config 를 만들어서 따로 저장할 예정.
Contact contact = contactArrayList.get(index); // 인덱스에 해당하는 id 가져와
handler.deleteContact(contact);
// 해당 인덱스의 데이터를 삭제한다.
contactArrayList.remove(index);
// 어댑터에게 화면갱신하라고 알랴줌
notifyDataSetChanged();
// 화면은 어댑터에게 맡기면 된다.
}
});
builder.setNegativeButton("NO", null);
builder.show();
}
}
}
app / java / com.bpdev.contacts / model / Contact.java
package com.bpdev.contacts.model;
import java.io.Serializable;
public class Contact implements Serializable {
public int id;
public String name;
public String phone;
public Contact(String name, String phone) {
this.name = name;
this.phone = phone;
}
// Overloading
public Contact(int id, String name, String phone) {
this.id = id;
this.name = name;
this.phone = phone;
}
}
app / java / com.bpdev.contacts / data / DatabaseHandler.java
package com.bpdev.contacts.data;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
import com.bpdev.contacts.model.Contact;
import java.util.ArrayList;
public class DatabaseHandler extends SQLiteOpenHelper {
// extends SQLiteOpenHelper 요구사항 2
public DatabaseHandler(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
// extends SQLiteOpenHelper 요구사항 1 두 개의 override
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
// 테이블 생성 SQLite 구문 작성
String query = "create table contact ( id integer primary key autoincrement, name text, phone text);";
sqLiteDatabase.execSQL(query);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
// 기존 테이블 삭제, 새 테이블 만드는 코드 작성
}
// 필요한 CRUD 관련 메소드들을 만들어 준다.
public void addContact(Contact contact){
SQLiteDatabase db = getWritableDatabase();
String query = "insert into contact (name, phone) values ( ?, ? )";
String[] record = { contact.name, contact.phone }; // 배열로 만들어 주었다. // Contact 클래스에 있는 변수들 public으로 설정해 줌.
db.execSQL(query, record);
db.close();
}
// 저장된 연락처를 모두 가져오는 메소드
// MainActivity로 먼저 가서 Adapter를 만든다.
public ArrayList<Contact> getAllContacts(){
SQLiteDatabase db = getWritableDatabase();
String query = "select * from contact";
Cursor cursor = db.rawQuery(query, null);
// 아래 Contact를 담을 ArrayList 만들자 .
ArrayList<Contact> contactArrayList = new ArrayList<>();
if(cursor.moveToFirst()){
do {
int id = cursor.getInt(0);
String name = cursor.getString(1);
String phone = cursor.getString(2);
// 여기서의 0,1,2는 컬럼 순서다.
Contact contact = new Contact(id, name, phone);
contactArrayList.add(contact);
} while (cursor.moveToNext());
} // 만약 받아온 데이터가 있다면 첫번째 데이터부터 실행하라. 매뉴얼에 작성되어 있는 코드
return contactArrayList;
}
public void deleteContact(Contact contact){
SQLiteDatabase db = getWritableDatabase();
String query = "delete from contact where id = ?";
String[] record = { contact.id + "" };
db.execSQL(query, record);
db.close();
}
public void updateContact(Contact contact){
SQLiteDatabase db = getWritableDatabase();
String query = "update contact set name = ?, phone = ? where id = ?";
String[] record = { contact.name, contact.phone, contact.id+"" };
db.execSQL(query, record);
db.close();
}
}
app / java / com.bpdev.contacts / AddActivity.java
package com.bpdev.contacts;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.bpdev.contacts.data.DatabaseHandler;
import com.bpdev.contacts.model.Contact;
import com.google.android.material.snackbar.Snackbar;
public class AddActivity extends AppCompatActivity {
EditText editName;
EditText editPhone;
Button btnSave;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
editName = findViewById(R.id.editName);
editPhone = findViewById(R.id.editPhone);
btnSave = findViewById(R.id.btnSave);
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String name = editName.getText().toString().trim();
String phone = editPhone.getText().toString().trim();
if (name.isEmpty() || phone.isEmpty()){
Snackbar.make(btnSave, "필수항목을 입력하세요.", Snackbar.LENGTH_SHORT).show();
return;
}
// 이름 전번 메모리에 저장
Contact contact = new Contact(name, phone);
// 이름 전번 DB에 저장
// DB관련 클래스 만들고 왔다.
// DB에 저장하는 건 DatabaseHandler가 한다.
// 1. db handler를 만든다.
DatabaseHandler handler = new DatabaseHandler(AddActivity.this, "contact_db", null, 1); // 이름들을 정해준다.
handler.addContact(contact); // db에 저장!
Toast.makeText(AddActivity.this, "잘 저장되었습니다.", Toast.LENGTH_SHORT).show();
finish();
}
});
}
}
app / java / com.bpdev.contacts / UpdateActivity.java
package com.bpdev.contacts;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.bpdev.contacts.data.DatabaseHandler;
import com.bpdev.contacts.model.Contact;
import com.google.android.material.snackbar.Snackbar;
import java.net.CookieHandler;
import java.util.ArrayList;
public class UpdateActivity extends AppCompatActivity {
EditText editName;
EditText editPhone;
Button btnSave;
Contact contact;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_update);
editName = findViewById(R.id.editName);
editPhone = findViewById(R.id.editPhone);
btnSave = findViewById(R.id.btnSave);
// main에서 선택한 row의 Contact.name과 Contact.phone 셋팅
contact = (Contact) getIntent().getSerializableExtra("contact"); // data type을 맞춰주도록 한다.
editName.setText(contact.name);
editPhone.setText(contact.phone);
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String name = editName.getText().toString().trim();
String phone = editPhone.getText().toString().trim();
if (name.isEmpty() || phone.isEmpty()) {
Snackbar.make(btnSave, "필수항목을 입력하세요.", Snackbar.LENGTH_SHORT).show();
return;
}
contact.name = name;
contact.phone = phone;
DatabaseHandler handler = new DatabaseHandler(UpdateActivity.this, "contact_db", null, 1);
handler.updateContact(contact);
Toast.makeText(UpdateActivity.this, "잘 저장되었습니다.", Toast.LENGTH_SHORT).show();
finish();
}
});
}
}