일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 막내의막무가내
- 부스트코스
- 막내의막무가내 안드로이드 에러 해결
- 2022년 6월 일상
- 막무가내
- 막내의막무가내 안드로이드
- 막내의 막무가내 알고리즘
- 막내의막무가내 플러터 flutter
- Fragment
- 막내의막무가내 rxjava
- 주엽역 생활맥주
- 막내의막무가내 코볼 COBOL
- flutter network call
- 프로그래머스 알고리즘
- 주택가 잠실새내
- 막내의 막무가내
- 막내의막무가내 프로그래밍
- 안드로이드
- 막내의막무가내 일상
- 막내의막무가내 알고리즘
- 막내의막무가내 안드로이드 코틀린
- 부스트코스에이스
- 안드로이드 sunflower
- 안드로이드 Sunflower 스터디
- 막내의막무가내 코틀린 안드로이드
- 막내의막무가내 코틀린
- 프래그먼트
- 막내의막무가내 플러터
- 막내의막무가내 SQL
- 막내의막무가내 목표 및 회고
- Today
- Total
막내의 막무가내 프로그래밍 & 일상
[안드로이드] Room 데이터베이스 본문
이전에 SqliteDatabse와 Relam은 간략하게라도 써봤었는데 Room은 써본적이 없어 이번에 공부도할겸 간략하게 써보고 정리를 해봤다.
https://www.youtube.com/watch?v=LRMfm458E3k
먼저 오준석 강사님의 강의를 수강하고 여러 블로그를 참조했다.
https://codelabs.developers.google.com/codelabs/android-room-with-a-view/#8
그리고 이 사이트대로 코드를 레퍼지토리로 짜볼려고 했으나 짜다가 중간에 좀 복잡해져서 나중에 실력이 향상되면 해보기로한다.. MVVM패턴을 사용하는 것 같은데 내가 아직 MVVM패턴을 모르고 저 사이트대로 하는건 배보다 배꼽이 더커지는 것 같다 생각했다. 나중에 MVVM 레퍼지토리 패턴(?)을 공부한 후에 해봐야겠다.
먼저 Room 라이브러리에 대한 설명은 다음과 같다.
룸 라이브러리는 SQLite의 모든 기능을 활용하면서보다 강력한 데이터베이스에 액세스 할 수 있도록 SQLite를 통해 추상화 계층을 제공합니다. (출처 : https://developer.android.com/topic/libraries/architecture/room)
Room도 Relam과 마찬가지로 ORM(Object Relational Mapping) 라이브러리이다고 안드로이드 Jetpack 아키텍처에 속해있다. Room은 Sqlite에 비해 많은 편리함과 여러가지 기능들을 제공한다. 그에대한 것은 다음 블로그나 다른 블로그에 많이써져있으므로 참고하도록하자.
난 레포지토리클래스를 사용하지않고 AsyncTask를 액티비티에서 구현하는식으로 구현해봤다.
들어가기 앞서 Room은 @Entity, @Dao, @Database 로 이루어진다.
이제 코드를 통해 살펴보도록하자 (주석참고)
1. 먼저 Todo라는 모델클래스를 생성한다. (프라이머리 키를 설정할 수 있고 테이블이름이나 컬럼명도 변경이 가능하다. 만약 테이블이름이나 컬럼명을 따로 설정하지않으면 원래의 클래스이름과 변수명으로 매칭된다. 이 밖에 여러가지 기능이 있으나 필요해질때 구글링해서 찾아보도록 하자.
package com.example.myroom;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
//@Entity(primaryKeys = {"firstName", "lastName"}) =>
//@Entity(tableName = "Todo")
@Entity
public class Todo {
@PrimaryKey(autoGenerate = true) //autoGenerate는 알아서 id를 1씩 증가시켜준다. autoincrement와 똑같
private int id;
//@ColumnInfo(name = "first_name") ==>컬럼명 변수명과 다르게 사용 가능
private String title;
public Todo(String title) {
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String toString() {
return "\n id=> " + this.id + " , title=> " + this.title;
}
}
2. TodoDao 인터페이스를 만들어서 쿼리문을 작성하도록한다. 어노테이션을 보면 대충 짐작갈거라고 본다. (쿼리문이 작성되지않고 그냥 @Delete 이렇게 되있는거같은 경우는 room에서 알아서 매개변수로 받은 객체를 찾아 제거해준다. 똑똑해라...) LiveData<>로 감싸면 주석에 써있듯이 디비에 변화가 생기면 해당 변화를 감지하고 백그라운드로 작업을 처리할 수 있게해준다. 메인액티비티에서 옵저버와 함께 사용된다.
참고로 디비 접근 즉 CRUD 작업은 모두 백그라운드로 실행되어야한다. 안그럼 에러난다.
package com.example.myroom;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import java.util.List;
//모든 디비 CRUD작업은 메인스레드가아닌 백그라운드로 작업해야한다. (단, 라이브데이터는 반응시 자기가 알아서 백그라운드로 작업을 처리해준다. 굳)
@Dao
public interface TodoDao {
@Query("SELECT * FROM Todo")
LiveData<List<Todo>> getAll(); //LiveData => Todo테이블에 있는 모든 객체를 계속 관찰하고있다가 변경이 일어나면 그것을 자동으로 업데이트하도록한다.
//getAll() 은 관찰 가능한 객체가 된다.(즉 디비변경시 반응하는)
@Insert
void insert(Todo todo);
@Update
void update(Todo todo);
@Delete
void delete(Todo todo);
@Query("DELETE FROM Todo")
void deleteAll();
}
3. AppDatabase 혹은 TodoDatabase라는 이름으로(자유) 데이터베이스 생성클래스를 만든다. 데이터베이스 객체는 생성하는 비용이 크므로 싱글톤으로 해야한다. Dao클래스를 포함하고있다.
package com.example.myroom;
import android.content.Context;
import android.os.AsyncTask;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
@Database(entities = {Todo.class}, version = 1)
public abstract class TodoDatabase extends RoomDatabase {
//데이터베이스를 매번 생성하는건 리소스를 많이사용하므로 싱글톤이 권장된다고한다.
private static TodoDatabase INSTANCE;
public abstract TodoDao todoDao();
//디비객체생성 가져오기
public static TodoDatabase getAppDatabase(Context context){
if(INSTANCE == null){
INSTANCE = Room.databaseBuilder(context, TodoDatabase.class , "todo-db")
.build();
/*INSTANCE = Room.databaseBuilder(context, TodoDatabase.class , "todo-db")
.allowMainThreadQueries() =>이걸 추가해서 AsyncTask를 사용안하고 간편하게할수있지만 오류가많아 실제 앱을 만들때 사용하면 안된다고한다.
.build();*/
}
return INSTANCE;
}
//디비객체제거
public static void destroyInstance() {
INSTANCE = null;
}
}
4. 마지막으로 메인액티비티에서 갖다가 쓰면된다.(주석참고) LiveData였던 getAll()과 옵저버를 통해 디비변화를 감지하고 그 때 할 일을 구현할 수 있다.
package com.example.myroom;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private EditText mTodoEditText;
private TextView mResultTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTodoEditText = findViewById(R.id.et_todo);
mResultTextView = findViewById(R.id.tv_content);
//디비생성
TodoDatabase db = TodoDatabase.getAppDatabase(this);
//UI 갱신 (라이브데이터 Observer 이용, 해당 디비값이 변화가생기면 실행됨)
db.todoDao().getAll().observe(this, new Observer<List<Todo>>() {
@Override
public void onChanged(List<Todo> todos) {
mResultTextView.setText(todos.toString());
}
});
//DB 데이터 불러오기 (SELECT)
mResultTextView.setText(db.todoDao().getAll().toString());
//추가버튼시 DB에 데이터 INSERT
findViewById(R.id.btn_add).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mTodoEditText.getText().toString().trim().length() <= 0) {
Toast.makeText(MainActivity.this, "한글자 이상입력해주세요.", Toast.LENGTH_SHORT).show();
}else{
new InsertAsyncTask(db.todoDao()).execute(new Todo(mTodoEditText.getText().toString()));
mTodoEditText.setText("");
}
}
});
}
//메인스레드에서 데이터베이스에 접근할 수 없으므로 AsyncTask를 사용하도록 한다.
public static class InsertAsyncTask extends AsyncTask<Todo, Void, Void> {
private TodoDao mTodoDao;
public InsertAsyncTask(TodoDao todoDao){
this.mTodoDao = todoDao;
}
@Override //백그라운드작업(메인스레드 X)
protected Void doInBackground(Todo... todos) {
//추가만하고 따로 SELECT문을 안해도 라이브데이터로 인해
//getAll()이 반응해서 데이터를 갱신해서 보여줄 것이다, 메인액티비티에 옵저버에 쓴 코드가 실행된다. (라이브데이터는 스스로 백그라운드로 처리해준다.)
mTodoDao.insert(todos[0]);
return null;
}
}
}
5. 결과화면이다 . 글을 추가하면 라이브데이터(getAll, 옵저버)가 반응해서 밑 TextView에 해당 작성한게 자동으로 추가됨을 볼 수 있따.
이상 room을 간략하게 살펴보았고 애용하도록해야겠다. 또 room에 다양한 기능과 복잡한 기능들이 많은데 더 공부하고 알아봐야겠다.
코틀린으로 되있는 코드나 좀 더 설명이 필요하시다면 다음 링크를 참고해주세요 :)
youngest-programming.tistory.com/179
댓글과 공감은 큰 힘이됩니다. 감사합니다.!
'안드로이드 > 자바 & Previous' 카테고리의 다른 글
[안드로이드] Retrofit2 @Body @Field 차이 (5) | 2019.11.07 |
---|---|
[안드로이드] 부스트코스 7단원 멀티미디어 내용요약 (0) | 2019.09.03 |
[안드로이드] Parcelabe vs Serializable 성능차이 (0) | 2019.08.14 |
[안드로이드] 특정 텍스트 복사 ClipboardManager (0) | 2019.08.13 |
[안드로이드] 프래그먼트 백스택 (fragment backstack) (4) | 2019.08.10 |