Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

MVVM패턴 실습을 위한 간단 TODOLIST 프로젝트 java.ver

DDH-975/Todo-MVVM-Java

Repository files navigation

Todo-MVVM-Java

프로젝트 설명

이 프로젝트는 MVVM 패턴 실습에 초점을 맞춘 간단한 TodoList 앱입니다.
Room 데이터베이스를 활용하여 로컬에 데이터를 저장하며, View ↔ ViewModel ↔ Model 간의 역할을 분리하는 것을 실습하였습니다.


🛠️ 기술 스택

  • 언어 (Languages): Java, XML
  • 개발 환경: Android Studio
  • 아키텍처 (Architecture): MVVM (Model-View-ViewModel)
  • 데이터베이스 (Database): Room

🔄 앱 구조 및 흐름

앱은 Room DB → Repository → ViewModel → View 흐름을 기반으로 동작합니다.


1. Room DB (Model 계층)

DB 접근을 위한 Dao 인터페이스를 정의합니다.
LiveData를 반환하여 데이터 변경 시 자동으로 UI에 반영되도록 합니다.

@Dao
public interface TodoDao {
 @Query("SELECT * FROM TODOENTITY")
 LiveData<List<TodoEntity>> getAllData();
 @Insert(onConflict = OnConflictStrategy.REPLACE)
 void setInsertTodo(TodoEntity todo);
 @Query("DELETE FROM TodoEntity")
 void deleteAllTodo();
 @Query("DELETE FROM TodoEntity WHERE id = :id")
 void deleteDataWhereId(int id);
}

Repository는 DB 접근 로직을 캡슐화하여 ViewModel이 데이터 소스를 직접 알지 않아도 되도록 합니다. 비동기 처리를 위해 Executor를 사용합니다.

public class TodoRepository {
 private TodoDao dao;
 private LiveData<List<TodoEntity>> allData;
 private Executor executor = Executors.newSingleThreadExecutor();
 public TodoRepository(Application application) {
 TodoDB db = TodoDB.getDatabase(application);
 dao = db.dao();
 allData = dao.getAllData();
 }
 public LiveData<List<TodoEntity>> getAllData() {
 return allData;
 }
 public void InsertData(TodoEntity todoEntity) {
 executor.execute(() -> dao.setInsertTodo(todoEntity));
 }
 public void deleteAllData() {
 executor.execute(() -> dao.deleteAllTodo());
 }
 public void deleteDataWhereId(int id) {
 executor.execute(() -> dao.deleteDataWhereId(id));
 }
}

ViewModel은 Repository를 통해 데이터를 가져오고, LiveData로 관리하여 View에 전달합니다. UI 관련 로직과 데이터 보존 역할을 담당합니다.

public class Todo_ViewModel extends AndroidViewModel {
 private TodoRepository repository;
 private LiveData<List<TodoEntity>> liveData;
 public Todo_ViewModel(@NonNull Application application) {
 super(application);
 repository = new TodoRepository(application);
 liveData = repository.getAllData();
 }
 public LiveData<List<TodoEntity>> getAllData() {
 return liveData;
 }
 public void insertData(TodoEntity data) {
 repository.InsertData(data);
 }
 public void deleteAllData() {
 repository.deleteAllData();
 }
 public void deleteDataWhereId(int id) {
 repository.deleteDataWhereId(id);
 }
}

💡 ViewModel이 아닌 AndroidViewModel을 상속한 이유

  • TodoRepository에서 Room Database를 초기화할 때 Application Context가 필요하기 때문입니다.
  • 일반 ViewModel은 Context에 접근할 수 없지만, AndroidViewModel은 생성자를 통해 Application 객체를 전달받을 수 있습니다.
  • 이를 통해 ViewModel 내부에서 getApplication()을 사용하여 안전하게 Room DB등 Context 기반 리소스를 초기화할 수 있습니다.

즉, View와 분리된 상태 관리 역할을 유지하면서도, 앱 전역 자원에 접근할 수 있도록 하기 위해 AndroidViewModel을 사용하였습니다.


4. View (MainActivity & Adapter)

ViewModel 초기화 (MainActivity)

MainActivity에서는 ViewModelProvider.AndroidViewModelFactory를 사용해 Todo_ViewModel 인스턴스를 생성합니다.
이는 Todo_ViewModelAndroidViewModel을 상속받아 Application 객체를 필요로 하기 때문입니다.

viewModel = new ViewModelProvider( this,ViewModelProvider.AndroidViewModelFactory
.getInstance(getApplication())).get(Todo_ViewModel.class);

AndroidViewModelFactory는 내부적으로 getApplication()을 전달해 Todo_ViewModel의 생성자를 올바르게 호출합니다.


LiveData 관찰 (자동 업데이트)

View는 사용자 입력을 처리하고, ViewModel의 LiveData관찰(Observer) 하여 자동으로 UI를 업데이트합니다.

viewModel.getAllData().observe(this, todoData -> {
 adapter.setData(todoData);
 adapter.notifyDataSetChanged();
});

➡️ LiveData 값이 변경될 때마다 RecyclerView UI가 자동 갱신됩니다.


사용자 입력 처리

binding.btnAdd.setOnClickListener(it -> {
 String todoList = binding.etTodo.getText().toString().trim();
 if (todoList.isEmpty()) {
 Toast.makeText(this, "할일을 입력해주세요", Toast.LENGTH_SHORT).show();
 } else {
 TodoEntity data = new TodoEntity();
 data.setTodo(todoList);
 viewModel.insertData(data);
 }
});

삭제 콜백 인터페이스

public interface OndeleteClickListener {
 void deleteClick(int id);
}

RecyclerView Adapter

@Override
public void onBindViewHolder(@NonNull Todo_Adpater.Viewholder holder, int position) {
 holder.todo.setText(data.get(position).getTodo());
 holder.delete.setOnClickListener(it -> {
 listener.deleteClick(data.get(position).getId());
 });
}

➡️ 삭제 버튼 클릭 → Adapter 콜백 실행 → ViewModel의 deleteDataWhereId() 호출 → Repository → Room DB 삭제 → LiveData 변경 → UI 자동 반영


📌 전체 데이터 흐름 요약

  1. 사용자 입력 (추가/삭제)MainActivityViewModel 호출
  2. ViewModelRepository 통해 DB 요청 위임
  3. RepositoryRoom DB 접근 (비동기 처리)
  4. DB 변경LiveData 업데이트 → ViewModelView 자동 반영

📱 주요 기능

  • Todo 추가
  • Todo 삭제
  • Room DB를 통한 데이터 영구 저장
  • LiveData & Observer를 통한 실시간 UI 업데이트

📊 구조 다이어그램

사용자 입력
 ↓
 View (MainActivity / Adapter)
 ↓
 ViewModel (Todo_ViewModel)
 ↓
 Repository (TodoRepository)
 ↓
 Room DB (TodoDao, TodoEntity)
 ↓
 LiveData 업데이트
 ↓
 View 자동 반영 (Observer)

실행 화면 (Screenshots & GIFs)

About

MVVM패턴 실습을 위한 간단 TODOLIST 프로젝트 java.ver

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

AltStyle によって変換されたページ (->オリジナル) /