Android
[Android] MVVM 패턴 적용 - ACC 예제
팽팽
2022. 10. 11. 23:01
- DAO ? DB의 data에 접근하기 위한 객체
< viewmodel 적용 이전>
Todo.class (Room)
: id, title이 정의된 데이터
package org.techtown.myapplication;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity //룸에서 사용할수 있는 entity
public class Todo {
@PrimaryKey(autoGenerate = true)
private int id;
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 "Todo{" +
"id=" + id +
", title='" + title + '\'' +
'}';
}
}
TodoDao.interface
: Todo에 접근하기 위한 데이터 접근 객체
: 조회, 삽입 , 삭제등의 메서드를 정의함 getAll() -> Todo의 모든 값 조회
: LiveData로 지정함
package org.techtown.myapplication;
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;
//Todo에 접근하기 위한 Data access object
@Dao
public interface TodoDao {
//Todo에 어떤 동작 제공할지 정의
@Query("SELECT * FROM Todo")
LiveData<List<Todo>> getAll();
@Insert
void insert(Todo todo);
@Update
void update(Todo todo);
@Delete
void delete(Todo todo);
}
AppDatabase.class
: RoomDB 상속후 tododao 구체화
package org.techtown.myapplication;
import androidx.room.Database;
import androidx.room.RoomDatabase;
@Database(entities = {Todo.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract TodoDao todoDao(); // todo조작
}
MainActivity.class
: observe를 통해 값이 바뀌면 갱신함
package org.techtown.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.room.Room;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
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.todoEdit);
mResultTextview = findViewById(R.id.result_text);
final AppDatabase db = Room.databaseBuilder(this,AppDatabase.class,"todo-db")
.build();
//UI 갱신
db.todoDao().getAll().observe(this,todos -> {
mResultTextview.setText(todos.toString());
});
// 버튼 클릭시 db에 insert
findViewById(R.id.addBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new InsertAsyncTask(db.todoDao())
.execute(new Todo(mTodoEditText.getText().toString()));
}
});
}
private static class InsertAsyncTask extends AsyncTask<Todo, Void, Void> {
private TodoDao mTodoDao;
public InsertAsyncTask(TodoDao todoDao){
this.mTodoDao = todoDao;
}
//Room을 비동기로 사용
@Override
protected Void doInBackground(Todo... todos) {
mTodoDao.insert(todos[0]);
return null;
}
}
}
< ViewModel 적용 후 >
MainActivity.class
: 원래는 db 선언, 버튼 클릭시 insert가 MainActivity에 선언되어 있었지만,
UI와 기능을 분리하기 위해
MainActivity에서 viewprovider를 선언하고 따로 선언된 MainViewModel의 메서드를 불러옴
observe()로 변하는 ui를 관찰함
package org.techtown.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.room.Room;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
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.todoEdit);
mResultTextview = findViewById(R.id.result_text);
//ViewModelPrivider로 ViewModel 사용 가능
MainViewModel viewModel = new ViewModelProvider(this)
.get(MainViewModel.class);
// getall시 결과가 변경될때마다 todo로 들어옴
// 관찰하다가 ui 갱신
viewModel.getAll().observe(this, new Observer<List<Todo>>() {
@Override
public void onChanged(List<Todo> todos) {
mResultTextview.setText(todos.toString());
}
});
// 버튼 클릭시 db에 insert
// 값이 안 바뀔수도 있는 경우엔 ui갱신을 하지 않아도 됨
findViewById(R.id.addBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
viewModel.insert(new Todo(mTodoEditText.getText().toString()));
}
});
}
// 원래 아래 코드를 onClick()에 썼다면 aac패턴에서는 onChanged안에 넣기
// mResultTextview.setText(db.todoDao().getAll().toString());
}
MainViewModel.class
: 여기서 db선언, LiveData 선언, insert() 메서드 선언을 따로 해줌
getAll() 을 호출하면 tododao의 getall을 호출해줌
package org.techtown.myapplication;
import android.app.Application;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import androidx.room.Room;
import java.util.List;
public class MainViewModel extends AndroidViewModel {
private AppDatabase db;
public MainViewModel(@NonNull Application application) {
super(application);
db = Room.databaseBuilder(application, AppDatabase.class,"todo-db")
.build();
}
public LiveData<List<Todo>> getAll() {
return db.todoDao().getAll();
}
public void insert(Todo todo) {
new InsertAsyncTask(db.todoDao())
.execute(todo);
}
private static class InsertAsyncTask extends AsyncTask<Todo, Void, Void> {
private TodoDao mTodoDao;
public InsertAsyncTask(TodoDao todoDao){
this.mTodoDao = todoDao;
}
@Override
protected Void doInBackground(Todo... todos) {
mTodoDao.insert(todos[0]);
return null;
}
}
//
// private AppDatabase db;
//
// public MainViewModel(@NonNull Application application) {
// super(application);
// // db 객체 생성
// db = Room.databaseBuilder(application, AppDatabase.class,"todo-db")
// .build();
//
// //.allowMainThreadQueries() //백그라운드 말고 메인 스레드에서 db사용
//
// public LiveData<List<Todo>> getAll() {
// return db.todoDao().getAll();
// }
// public void insert(Todo todo) {
//
// }
// }
}
-> MainActivity에는 ui관련 코드만 남게 됨
<DataBinding 적용후>