728x90
안녕하세요. 이번 시간에는 MVVM 패턴을 익히기 위해서 버튼을 클릭해 바뀐 데이터가 화면에 출력되는 예제를 만들어 보도록 하겠습니다.
MVVM 패턴의 역사
MVVM( Model View ViewModel )은 Microsoft 설계자 인 Cooper & Peters에 의해 탄생된 디자인 패턴입니다. 그리고 John Gossman에 의해 2005년 발표 되어 클라이언트 기반의 플랫폼에서 조금씩 사용되기 시작했습니다.
MVVM 패턴 구조
View : UI 요소를 표시하며 사용자가 발생한 이벤트를 받는 역할을 합니다.
ViewModel : UI 요소에 들어갈 데이터를 관리합니다. 그리고 Model과 View 사이의 다리 역할을 합니다.
Model : 데이터 전반적인 것을 처리하는 역할을 합니다.
MVVM 패턴의 장점
여러 화면이 있더라도 비슷한 데이터를 가지고 있는 애라면 같은 ViewModel을 공유할 수 있다.
(MVP 처럼 1:1이 아니기 때문)
ViewModel이 직접적으로 요소을 그리라고 View에게 요청하지 않기 때문
MVVM 패턴의 단점
간단한 프로젝트에 사용하기에는 과하다.
비교적 구현 구조가 복잡하고 설계가 수비지 않다.
MVVM 패턴 구현
이번 예제의 프로젝트 구조입니다.
XML 화면
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.example.snacker.viewmodel.ViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_info"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.25" />
<TextView
android:id="@+id/user_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="@{viewModel.winner}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.4" />
<Button
android:id="@+id/ok_btnview"
android:layout_width="114dp"
android:layout_height="68dp"
android:text="@string/main_btn"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.7" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
View
MainActivity
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding; // 상속 ViewDataBinding
ViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
Logger.d("Main_onCrete() 실행");
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main); // Activity Content's View - Layout 연결 & 반환 : ViewDataBinding을 상속하는 제네릭 타입
viewModel = new ViewModel(Database.getInstance());
binding.setViewModel(viewModel);
binding.okBtnview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Logger.d("버튼 클릭");
viewModel.getUser();
}
});
}
}
ViewModel
public class ViewModel extends BaseObservable {
private Database database;
private List<Person> items = new ArrayList<>();
private String winner;
public ViewModel(Database database){
Logger.d("ViewModel 생성자 실행 | DB(Model) 참조");
this.database = database;
this.database.setOnDatabaseListener(new Database.DatabaseListener() {
@Override
public void onChanged() {
Logger.d("리스너 실행");
winner = null;
winner = database.getWinner();
notifyChange();
}
});
}
public void getUser() {
Logger.d("db에게 user(winner)를 달라고 요청");
database.getUser();
}
public String getWinner(){
Logger.d("Winner 반환 (%s)", winner);
return winner;
}
}
Model
Database.java
public class Database {
private static Database instance;
private ArrayList<Person> personList = new ArrayList<>();
private String winner;
private DatabaseListener databaseListener;
private Database(){
Logger.d("Model인 Database 생성");
personList.add(new Person(0, "최OO"));
personList.add(new Person(1, "김OO"));
personList.add(new Person(2, "고OO"));
personList.add(new Person(3, "문OO"));
personList.add(new Person(4, "윤OO"));
}
public static Database getInstance() {
Logger.d("Model에 접근 할 수 있도록 DB 인스턴스 값 요청");
if (instance == null) {
instance = new Database();
}
return instance;
}
public void getUser() {
Logger.d("당첨자 획득");
winner = personList.get((int)(Math.random()*5)).getName();
notifyChange();
}
private void notifyChange() {
if (databaseListener != null) {
Logger.d("Model | Data 변경 되어 notify 하라고 알림");
databaseListener.onChanged();
}
}
public void setOnDatabaseListener(DatabaseListener databaseListener) {
Logger.d("DatabaseListener 구현 객체 참조 변수 세팅 (arg1 : %s)",databaseListener.getClass().getSimpleName());
this.databaseListener = databaseListener;
}
public String getWinner(){
return winner;
}
public interface DatabaseListener {
void onChanged();
}
}
Person.java
public class Person {
private long id;
private String name;
public Person(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
안에 있는 Logger 라이브러리는 아래 스틱코드를 이용해서 간단하게 구현이 가능합니다.
https://stickode.com/detail.html?no=2519
'안드로이드 자바' 카테고리의 다른 글
[JAVA][Android] 주사위 예제 만들기 (0) | 2021.10.27 |
---|---|
[JAVA][Android] 리사이클러뷰 아이템 이동, 스와이프로 삭제하기 (0) | 2021.10.26 |
[JAVA][Android] 안드로이드 - 알림 만들기 및 알림 탭하여 액티비티로 이동 (0) | 2021.10.21 |
[JAVA][Android] 안드로이드 - 스낵바(snackbar) (0) | 2021.10.20 |
[JAVA][Android] Messenger를 통해 Service 인터페이스 생성 (0) | 2021.10.17 |