[안드로이드] Room 사용방법 및 예제 + LiveData적용
안드로이드 - Room 사용방법 및 예제 + LiveData 적용
목차
- Room 개요 및 구성요소
- Room 사용방법 및 예제
- Gradle 설정
- 데이터 항목 정의 (Entity)
- 데이터 액세스 객체 정의 (DAO)
- 데이터베이스 정의 (Database)
- MainAcitivity 정의
- 실행결과
- Room + LiveData적용으로 실시간 변경사항 반영방법
1. Room 개요 및 구성요소
Room은 저장장치에 데이터를 저장하기 위해 기존 SQLite API 대신 사용할 것을 구글에서 권고하는 라이브러리입니다. 이전에 SQL 쿼리문에 익숙한 분들을 위해 SQLite 사용법을 정리하여 글을 올린적이 있는데, Room을 사용하면 안드로이드에서 기존 SQLite 보다 좀 더 편리하게 데이터 저장을 할 수 있습니다.
Room은 아래와 같이 크게 3가지의 주요 구성요소로 이루어져 있으며, 이를 작성하여 사용합니다.
- 데이터 항목 (Entity) : Database의 테이블로 사용하고자 하는 데이터를 정의합니다.
- 데이터 액세스 객체 (DAO) : Database의 데이터를 추가, 삭제, 수정, 검색하는데 사용되는 메서드를 정의합니다.
- 데이터베이스 (Database) : 데이터에 대한 액세스 포인트 역할을 하며, Database의 구성요소를 정의합니다.
2. Room 사용방법 및 예제
1) Gradle 설정
Room을 사용하기 위해서 먼저 아래와 같이 Gradle 설정을 해줍니다.
dependencies {
...
implementation "androidx.room:room-runtime:2.5.0"
annotationProcessor "androidx.room:room-compiler:2.5.0"
}
2) 데이터 항목 정의 (Entity)
데이터베이스에 저장할 데이터를 정의하기 위해서는 클래스명 위에 @Entity 어노테이션을 붙여줍니다.
여기서는 id와 name으로 구성된 User클래스를 만들도록 하겠습니다. id는 자동생성 되도록 @PrimaryKey 어노테이션을 붙여주고 생성자와 getter/setter를 만든후 toString 재정의를 해줍니다.
- User.java
@Entity
public class User {
@PrimaryKey(autoGenerate = true)
private int id;
private String name;
public User(String name) {
this.name = name;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override
public String toString() {
return "\nUser id=" + id + ", name=" + name;
}
}
3) 데이터 액세스 객체 정의 (DAO)
데이터 액세스 객체 DAO(Data Access Objects)는 @Dao 어노테이션을 붙이고 인터페이스(interface)로 만들어 줍니다.
UserDAO 클래스 안에는 User 데이터를 추가/삭제/수정/검색 할 수 있는 메소드를 만들어줍니다. 이때 간단한 동작은 SQL문 정의 없이도 가능하며, 복잡한 동작인 경우에는 SQL 쿼리문을 작성하여 사용할 수 있습니다.
- UserDAO.java
@Dao
public interface UserDAO {
@Query("SELECT * FROM User")
List<User> getAll();
@Insert
void insertUser(User user);
@Delete
void deleteUser(User user);
@Update
void updateUser(User user);
}
4) 데이터베이스 정의 (Database)
데이터베이스는 @Database 어노테이션을 붙이고 RoomDatabase를 상속받아 추상 클래스(abstract class)로 만들어줍니다. 그리고 아래 두가지가 정의되어 있어야 합니다.
- @Database 어노테이션에 데이터 항목 User.class를 entities에 정의해주어야 합니다.
- 데이터베이스 클래스 안에는 UserDAO를 반환하는 추상메소드를 정의해주어야 합니다.
추가로 RoomDatabase 인스턴스가 리소스를 많이 소비하므로 앱이 단일 프로스세에서 실행되면 싱글톤 패턴을 적용해야 한다고 구글에서 가이드하고 있습니다.
- AppDatabase.java
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDAO userDAO();
private static AppDatabase instance = null;
public static AppDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "user.db")
.allowMainThreadQueries() // 메인스레드에서 DB 작업가능하게 해줍니다. (테스트용?)
.build();
}
return instance;
}
public static void destroyInstance() {
instance = null;
}
}
5) MainActivity 정의
이제 Room을 사용할 준비는 끝났고, 간단하게 Room을 활용하여 입력데이터를 저장하는 예제를 만들어 보겠습니다.
- MainActivity.java
public class MainActivity extends AppCompatActivity {
private EditText editText_user;
private Button btn_user;
private TextView textView_result;
private AppDatabase db = null;
private String userList = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText_user = findViewById(R.id.editText_user);
btn_user = findViewById(R.id.btn_user);
textView_result = findViewById(R.id.textView_result);
db = AppDatabase.getInstance(this);
userList = db.userDAO().getAll().toString();
textView_result.setText(userList.substring(1, userList.length()-1));
btn_user.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
db.userDAO().insertUser(new User(editText_user.getText().toString()));
userList = db.userDAO().getAll().toString();
textView_result.setText(userList.substring(1, userList.length()-1));
}
});
}
}
- activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/editText_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="이름 입력" />
<Button
android:id="@+id/btn_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="저장하기" />
<TextView
android:id="@+id/textView_result"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="데이터 목록"
android:textSize="28dp" />
</LinearLayout>
6) 실행결과
3. Room + LiveData 적용으로 실시간 변경사항 반영방법
Room을 사용하여 DB조작시, LiveData를 이용하면 DB 변경사항을 실시간 모니터링 할 수 있습니다.
여기서는 앞에서 진행했던 예제를 LiveData가 적용되도록 변경해 보도록 하겠습니다.
1) UserDAO.java 변경사항
- 모니터링할 변수를 LiveData<>로 감싸줍니다.
@Dao
public interface UserDAO {
@Query("SELECT * FROM User")
//List<User> getAll();
LiveData<List<User>> getAll();
@Insert
void insertUser(User user);
@Delete
void deleteUser(User user);
@Update
void updateUser(User user);
}
2) MainActivity.java 변경사항
- observe( )메소드를 통해 데이터 변경시 실시간으로 화면 갱신이 이루어지도록 구현해 줍니다.
- 기존에 수동으로 화면에 뿌려주던 코드들은 주석처리합니다.
public class MainActivity extends AppCompatActivity {
private EditText editText_user;
private Button btn_user;
private TextView textView_result;
private AppDatabase db = null;
private String userList = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText_user = findViewById(R.id.editText_user);
btn_user = findViewById(R.id.btn_user);
textView_result = findViewById(R.id.textView_result);
db = AppDatabase.getInstance(this);
//userList = db.userDAO().getAll().toString();
//textView_result.setText(userList.substring(1, userList.length()-1));
db.userDAO().getAll().observe(this, new Observer<List<User>>() {
@Override
public void onChanged(List<User> users) {
textView_result.setText(users.toString().substring(1, users.toString().length()-1));
}
});
btn_user.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
db.userDAO().insertUser(new User(editText_user.getText().toString()));
//userList = db.userDAO().getAll().toString();
//textView_result.setText(userList.substring(1, userList.length()-1));
}
});
}
}