---
title: Android SDK로 Parse 객체 CRUD 처리하기
slug: docs-kr/android/data-objects/android-crud-tutorial
description: 안드로이드에서 Parse 객체 CRUD 구현: 생성, 읽기, 업데이트, 삭제 기능 안내
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-03-12T21:18:24.147Z
---

# 안드로이드에서 CRUD Parse 객체 사용하기

## 소개

이 섹션에서는 기본 CRUD 작업을 수행하는 안드로이드 애플리케이션을 구축할 것입니다. CRUD는 Create-Read-Update-Delete의 약자입니다. Parse에 데이터를 저장할 때는 ParseObject를 기반으로 하며, 각 객체는 JSON 호환 데이터의 키-값 쌍을 포함합니다.

Back4App 데이터베이스에 저장할 수 있는 값은 String, Number, Bool, Array, Object, Date, File, Pointer, Relation 및 null 유형일 수 있습니다.

데이터 유형에 대한 자세한 정보는 [여기](https://docs.parseplatform.org/js/guide/#data-types)를 클릭하여 확인할 수 있습니다.

이 튜토리얼은 <font color="#2166ae">`buildToolsVersion=30.0.2`</font> , <font color="#2166ae">`Compile SDK Version = 30.0.2`</font> 및 <font color="#2166ae">`targetSdkVersion 30`</font>

:::hint{type="success"}
**언제든지 GitHub 리포지토리를 통해 전체 프로젝트에 접근할 수 있습니다.**

- [Kotlin 예제 리포지토리](https://github.com/templates-back4app/android_crud_operations_kotlin)
- [Java 예제 리포지토리](https://github.com/templates-back4app/android_crud_operations_java)
:::

## 목표

우리가 달성할 목표의 미리보기입니다:

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/FxSZDT3Wxn0M43vVJGUkN_image.png" size="30" width="346" height="750" position="center" showCaption="false"}

## 필수 조건

:::hint{type="info"}
**이 튜토리얼을 완료하기 위해 필요한 것은:**

- [안드로이드 스튜디오](https://developer.android.com/studio/index.html)
- Back4App에서 생성된 앱.
  - **참고:&#x20;**&#x20;[새로운 Parse 앱 튜토리얼](https://www.back4app.com/docs/get-started/new-parse-app)을 따라 Back4App에서 Parse 앱을 만드는 방법을 배우세요.
- Back4App에 연결된 안드로이드 앱.
  - **참고:&#x20;**&#x20;[Parse SDK 설치 튜토리얼](https://www.back4app.com/docs/android/parse-android-sdk)을 따라 Back4App에 연결된 안드로이드 스튜디오 프로젝트를 만드세요.
- 안드로이드 4.1 (젤리빈) 이상을 실행하는 장치 (또는[ 가상 장치](https://developer.android.com/studio/run/managing-avds.html))입니다.
:::

## 우리의 Todo 앱 이해하기

안드로이드에서 Parse를 더 잘 이해하기 위해, ToDo 앱에서 구현된 CRUD 작업을 볼 수 있습니다. 이 애플리케이션은 작업을 등록하기 위한 제목 및 설명 텍스트 필드와 등록된 작업 목록이 있는 간단한 인터페이스를 가질 것입니다. 각 작업의 제목이나 설명을 업데이트할 수 있습니다.

:::hint{type="info"}
**참고:**

- 이 튜토리얼에서는 나만의 사용자 정의 경고 대화 상자를 만들 것입니다. 따라서 코드는 템플릿을 따르도록 구성됩니다. 자신의 디자인에 맞게 조정할 수 있습니다.
- 문제가 발생하면, [Kotlin](https://github.com/templates-back4app/android_crud_operations_kotlin) 및 [Java](https://github.com/templates-back4app/android_crud_operations_java)에 대한 GitHub 리포지토리를 확인하세요.
:::

## 시작해 봅시다!

다음 단계를 따르면 Back4App 데이터베이스에 작업을 저장하는 Todo 앱을 만들 수 있습니다.

## 1 - Todo 앱 템플릿 만들기

안드로이드 스튜디오로 가서 <font color="#2166ae">`activity_main.xml`</font> 레이아웃 파일을 찾으세요 <font color="#2166ae">`(Project/app/res/layout/activity_main.xml)`</font> 그리고 아래 코드를 자신의 코드로 교체하세요. 이 xml 코드는 우리의 <font color="#2166ae">`MainActivity의`</font> 디자인이 될 것이며, 우리는 이 뷰를 우리의 <font color="#2166ae">`MainActivity.java`</font> 클래스에 바인딩하고 사용할 것입니다.

```xml
1   <?xml version="1.0" encoding="utf-8"?>
2   <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3       xmlns:app="http://schemas.android.com/apk/res-auto"
4       xmlns:tools="http://schemas.android.com/tools"
5       android:layout_width="match_parent"
6       android:layout_height="match_parent"
7       tools:context=".MainActivity">
8
9       <!--Title-->>
10      <TextView
11          android:id="@+id/textView"
12          android:layout_width="0dp"
13          android:layout_height="wrap_content"
14          android:background="@color/blue_700"
15          android:gravity="center_horizontal"
16          android:padding="24dp"
17          android:text="TODO List"
18          android:textColor="@color/white"
19          app:layout_constraintEnd_toEndOf="parent"
20          app:layout_constraintStart_toStartOf="parent"
21          app:layout_constraintTop_toTopOf="parent" />
22
23      <!--We will open a pop-up view when clicked to this button-->>
24      <com.google.android.material.floatingactionbutton.FloatingActionButton
25          android:id="@+id/fab"
26          style="@style/Widget.MaterialComponents.FloatingActionButton"
27          android:layout_width="wrap_content"
28          android:layout_height="wrap_content"
29          android:layout_margin="16dp"
30          android:scaleType="centerInside"
31          android:src="@drawable/ic_baseline_add_24"
32          app:backgroundTint="@color/blue_700"
33          app:fabSize="normal"
34          app:layout_constraintBottom_toBottomOf="parent"
35          app:layout_constraintEnd_toEndOf="parent"
36          app:tint="@color/white" />
37
38      <!--We will show this text view when data list is empty-->>
39      <TextView
40          android:id="@+id/empty_text"
41          android:layout_width="wrap_content"
42          android:layout_height="wrap_content"
43          android:text="List is empty"
44          android:layout_marginTop="32dp"
45          android:textSize="20sp"
46          android:visibility="gone"
47          app:layout_constraintEnd_toEndOf="parent"
48          app:layout_constraintStart_toStartOf="parent"
49          app:layout_constraintTop_toBottomOf="@+id/textView" />
50
51      <!--We will adapt the data list to this RecyclerView-->
52      <androidx.recyclerview.widget.RecyclerView
53          android:id="@+id/recyclerView"
54          android:layout_width="0dp"
55          android:layout_height="0dp"
56          app:layout_constraintBottom_toBottomOf="parent"
57          app:layout_constraintEnd_toEndOf="parent"
58          app:layout_constraintStart_toStartOf="parent"
59          app:layout_constraintTop_toBottomOf="@+id/textView">
60      </androidx.recyclerview.widget.RecyclerView>
61  </androidx.constraintlayout.widget.ConstraintLayout>
```

## 2 - 객체 생성

create 함수는 제목과 설명을 가진 새로운 작업을 생성합니다.

TODO를 추가하기 위해, 화면에 나타나는 팝업에 제목과 설명 값을 입력하고, 이를 ParseObject에 설정한 후 이 객체를 저장합니다. 우리는 Parse가 제공한 함수를 사용하여 이 객체를 데이터베이스에 저장합니다.

:::hint{type="info"}
**참고:**

- 이 프로젝트에서는 나만의 사용자 정의 알림 대화 상자를 만들 것입니다. 원하는 대로 알림 대화 상자를 디자인하고 나중에 사용할 대화 상자의 뷰에 설정할 수 있습니다.
:::

:::CodeblockTabs
```java
1    openInputPopupDialogButton.setOnClickListener(fabButtonView -> {
2             AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
3             alertDialogBuilder.setTitle("Create a TODO");
4             alertDialogBuilder.setCancelable(true);
5             initPopupViewControls();
6             //We are setting our custom popup view by AlertDialog.Builder
7             alertDialogBuilder.setView(popupInputDialogView);
8             final AlertDialog alertDialog = alertDialogBuilder.create();
9             alertDialog.show();
10            saveTodoButton.setOnClickListener(saveButtonView -> saveTodo(alertDialog));
11            cancelUserDataButton.setOnClickListener(cancelButtonView -> alertDialog.cancel());
12        });   
13
14    //This is our saveTodo function
15    private void saveTodo(AlertDialog alertDialog) {
16        ParseObject todo = new ParseObject("Todo");
17        if (titleInput.getText().toString().length() != 0 && descriptionInput.getText().toString().length() != 0) {
18            alertDialog.cancel();
19            progressDialog.show();
20            todo.put("title", titleInput.getText().toString());
21            todo.put("description", descriptionInput.getText().toString());
22            todo.saveInBackground(e -> {
23                progressDialog.dismiss();
24                if (e == null) {
25                    //We saved the object and fetching data again
26                    getTodoList();
27                } else {
28                    //We have an error.We are showing error message here.
29                    showAlert("Error", e.getMessage());
30                }
31            });
32        } else {
33            showAlert("Error", "Please enter a title and description");
34        }
35    }
```

```kotlin
1    openInputPopupDialogButton?.setOnClickListener { fabButtonView ->
2             val alertDialogBuilder = AlertDialog.Builder(this@MainActivity)
3             alertDialogBuilder.setTitle("Create a TODO")
4             alertDialogBuilder.setCancelable(true)
5            initPopupViewControls()
6            //We are setting our custom popup view by AlertDialog.Builder
7            alertDialogBuilder.setView(popupInputDialogView)
8            val alertDialog = alertDialogBuilder.create()
9            alertDialog.show()
10            saveTodoButton?.setOnClickListener { saveButtonView ->
11                saveData(alertDialog)
12            }
13            cancelUserDataButton?.setOnClickListener { cancelButtonView ->
14                alertDialog.cancel()
15            }
16        }
17
18    //This is our saveTodo function
19    private fun saveData(alertDialog: AlertDialog) {
20        val todo = ParseObject("Todo")
21        if (titleInput?.text.toString().isNotEmpty() && descriptionInput?.text.toString().isNotEmpty()) {
22            alertDialog.cancel()
23            progressDialog?.show()
24            todo.put("title", titleInput?.text.toString())
25            todo.put("description", descriptionInput?.text.toString())
26            todo.saveInBackground { e ->
27                progressDialog?.dismiss()
28                if (e == null) {
29                    //We saved the object and fetching data again
30                    getTodoList()
31                } else {
32                    //We have an error.We are showing error message here.
33                    showAlert("Error", e.message!!)
34                }
35            }
36        } else {
37            showAlert("Error", "Please enter a title and description")
38        }
39    }
```
:::

## 3 - 객체 읽기

Parse가 제공한 기능을 사용하여, 우리는 ParseObject 목록으로 클래스의 모든 데이터를 가져올 수 있습니다. 아래와 같은 쿼리를 생성하고 Todo 클래스의 모든 데이터를 가져옵니다.

:::CodeblockTabs
```java
1     private void getTodoList() {
2         progressDialog.show();
3         ParseQuery<ParseObject> query = ParseQuery.getQuery("Todo");
4         query.orderByDescending("createdAt");
5         query.findInBackground((objects, e) -> {
6             progressDialog.dismiss();
7             if (e == null) {
8                 //We are initializing Todo object list to our adapter
9                 initTodoList(objects);
10            } else {
11                showAlert("Error", e.getMessage());
12            }
13        });
14    }
```

```kotlin
1     private fun getTodoList() {
2          progressDialog?.show()
3          val query = ParseQuery.getQuery<ParseObject>("Todo")
4          query.orderByDescending("createdAt")
5          query.findInBackground { objects, e ->
6              progressDialog?.dismiss()
7              if (e == null) {
8                  //We are initializing Todo object list to our adapter
9                  initTodoList(objects)
10             } else {
11                 showAlert("Error", e.message!!)
12             }
13         }
14    }
```
:::

이 함수에서는 반환된 목록을 매개변수로 사용하여 <font color="#2166ae">`어댑터`</font>, 이 <font color="#2166ae">`어댑터`</font>,를 <font color="#2166ae">`RecyclerView`</font>,에 설정하고, 이 목록의 각 객체의 값을 자신의 뷰에 출력합니다. 그리고 목록에 항목이 없으면, 우리는 <font color="#2166ae">`empty_text`</font>, 뷰를 <font color="#2166ae">`VISIBLE`</font>로 설정합니다.

:::CodeblockTabs
```java
1    private void initTodoList(List<ParseObject> list) {
2         if (list == null || list.isEmpty()) {
3             empty_text.setVisibility(View.VISIBLE);
4             return;
5         }
6         empty_text.setVisibility(View.GONE);
7
8         TodoAdapter adapter = new TodoAdapter(list, this);
9
10        recyclerView.setLayoutManager(new LinearLayoutManager(this));
11        recyclerView.setAdapter(adapter);
12    }
```

```kotlin
1    private fun initTodoList(list: List<ParseObject>?) {
2         if (list == null || list.isEmpty()) {
3             empty_text!!.visibility = View.VISIBLE
4             return
5         }
6         empty_text?.visibility = View.GONE
7
8         val adapter = TodoAdapter(list as ArrayList<ParseObject>, this)
9
10        recyclerView?.layoutManager = LinearLayoutManager(this)
11        recyclerView?.adapter = adapter
12    }
```
:::

## 4 - 객체 업데이트

어댑터의 뷰에서 편집 버튼을 사용하여 업데이트를 수행하고 있습니다. <font color="#2166ae">`MutableLivedata`</font>, Android에서 제공하는 객체로, 우리는 홈페이지에서 편집 버튼의 클릭 이벤트를 수신할 수 있습니다. 이 버튼이 클릭되면, 동일한 팝업을 열고 이번에는 클릭한 객체의 제목과 설명 값으로 이 팝업을 채웁니다. 그런 다음 사용자가 이 설명과 제목을 변경하고 저장을 누르면, 먼저 이 객체의 ID로 데이터베이스에서 가져온 후, 새로운 변수를 설정하고 객체를 다시 저장합니다.

:::hint{type="info"}
**참고:**

- MutableLiveData는 LiveData의 하위 클래스이며, 일부 속성(setValue/postValue)에 사용됩니다. 이러한 속성을 사용하여 UI에 쉽게 알릴 수 있습니다.
:::

:::CodeblockTabs
```java
1     adapter.onEditListener.observe(this, parseObject -> {
2              AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
3              alertDialogBuilder.setTitle("Update a TODO");
4              alertDialogBuilder.setCancelable(true);
5              //We are initializing PopUp Views with title and description parameters of ParseObject
6              initPopupViewControls(parseObject.getString("title"), parseObject.getString("description"));
7              alertDialogBuilder.setView(popupInputDialogView);
8              final AlertDialog alertDialog = alertDialogBuilder.create();
9              alertDialog.show();
10             saveTodoButton.setOnClickListener(saveTodoButtonView -> {
11                 if (titleInput.getText().toString().length() != 0 && descriptionInput.getText().toString().length() != 0) {
12                     alertDialog.cancel();
13                     progressDialog.show();
14                     parseObject.put("title", titleInput.getText().toString());
15                     parseObject.put("description", descriptionInput.getText().toString());
16                     parseObject.saveInBackground(e1 -> {
17                         progressDialog.dismiss();
18                         if (e1 == null) {
19                             getTodoList();
20                         } else {
21                             showAlert("Error", e1.getMessage());
22                         }
23                     });
24                 } else {
25                     showAlert("Error", "Please enter a title and description");
26                 }
27             });
28             cancelUserDataButton.setOnClickListener(cancelButtonView -> alertDialog.cancel());
29         });
```

```kotlin
1     adapter.clickListenerToEdit.observe(this@MainActivity, { parseObject ->
2              val alertDialogBuilder = AlertDialog.Builder(this@MainActivity)
3              alertDialogBuilder.setTitle("Update a TODO")
4              alertDialogBuilder.setCancelable(true)
5
6              //We are initializing PopUp Views with title and description parameters of ParseObject
7
8              initPopupViewControls(
9                  parseObject.getString("title")!!,
10                 parseObject.getString("description")!!
11             )
12
13             alertDialogBuilder.setView(popupInputDialogView)
14             val alertDialog = alertDialogBuilder.create()
15             alertDialog.show()
16
17             saveTodoButton?.setOnClickListener { saveButtonView ->
18                 if (titleInput?.text.toString().isNotEmpty() && descriptionInput?.text.toString().isNotEmpty()) {
19                     alertDialog.cancel()
20                     progressDialog?.show()
21                     parseObject.put("title", titleInput?.text.toString())
22                     parseObject.put("description", descriptionInput?.text.toString())
23                     parseObject.saveInBackground { e1 ->
24                         progressDialog?.dismiss()
25                         if (e1 == null) {
26                             getTodoList()
27                         } else {
28                             showAlert("Error", e1.message!!)
29                         }
30                     }
31                 } else {
32                     showAlert("Error", "Please enter a title and description")
33                 }
34             }
35         })
```
:::

## 5 - 객체 삭제

우리는 어댑터의 뷰에서 삭제 버튼의 클릭 이벤트를 듣습니다. <font color="#2166ae">`MutableLivedata` </font>홈 페이지의 객체와 마찬가지로 편집 버튼에서. 삭제 버튼이 클릭되면, ParseObject의 객체 ID를 삭제 함수에 매개변수로 제공하고 이 객체를 데이터베이스에서 삭제합니다.

:::CodeblockTabs
```java
1    adapter.onDeleteListener.observe(this, parseObject -> {
2             progressDialog.show();
3             parseObject.deleteInBackground(e -> {
4                 progressDialog.dismiss();
5                 if (e == null) {
6                     //We deleted the object and fetching data again.
7                     getTodoList();
8                 } else {
9                     showAlert("Error",e.getMessage());
10                }
11            });
12        });
```

```kotlin
1    adapter.onDeleteListener.observe(this@MainActivity, { parseObject ->
2             progressDialog?.show()
3             parseObject.deleteInBackground { e ->
4                 progressDialog?.dismiss()
5                 if (e == null) {
6                     //We deleted the object and fetching data again.
7                     getTodoList()
8                 } else {
9                     showAlert("Error", e.message!!)
10                }
11            }
12        })
```
:::

## 완료되었습니다!

이 시점에서, 당신은 Android에서 Parse로 기본 CRUD 작업을 수행하는 방법을 배웠습니다.
