Android (안드로이드)

[Android] 디자인 패턴 - MVVM 패턴 / 예제

Oscar:) 2024. 2. 16. 16:38

 

 

이번엔 MVVM 패턴에 대해 알아보자.

 

 

디자인 패턴이 뭔지 모르겠다면 다음 포스팅을 보고 오자.

 

 

디자인 패턴 & MVC 패턴에 대한 포스팅이다.

 

 

[Android] 디자인 패턴 - MVC 패턴 / 예제

디자인 패턴 중 MVC 패턴에 대해 알아보자. 안드로이드에서 적용하는 MVC 패턴이다. 디자인 패턴이란? 소프트웨어의 개발 방식을 문서로 공식화 한 것. 개발 중 자주 나타나는 과제를 해결하기 위

oscarstory.tistory.com

 

 


 

MVVM 패턴

 

 

MVP 패턴을 기반으로 생겨났으며,

Presenter의 자리를 ViewModel이 대체했다고 볼 수 있다.

 

Model + View + ViewModel 의 약어로 MVVM이라 칭한다.

 

 

ViewModel은 MVP 패턴의 Presenter와 동일한 역할을 한다.

View와 Model 사이에서 중개자 역할을 해준다.

 

그렇기에 MVP 패턴과 마찬가지로 View와 Model이 확실하게 분리되었다.

 

 

하지만 MVP와 명확한 차이점도 있는데,

View와 ViewModel간의 의존성도 줄였다는 것이다.

 

 

 

MVP 패턴 구조와 유사해 보이지만,

ViewModel에서 View에게 뷰 업데이트를 적용하는 부분을 연한 회색으로 표현했다.

 

View에서 사용자의 입력을 받고 ViewModel에게 알리는 과정은 MVP 패턴과 동일하지만,

반대로 ViewModel이 View에게 알릴 때는 직접적으로 전달하지 않는다는 것이다.

 

 

 

 

✅ Model

 

- 데이터와 비즈니스 로직을 주로 관리한다.

- ViewModel 로부터 명령을 전달 받고 데이터의 상태를 변경시킨다.

- 데이터의 상태가 변경됨녀 다시 ViewModel에게 알린다.

 

 

✅ View

 

- View · Layout 등 화면을 처리하는 곳이면서,

안드로이드의 경우 Activity · Fragment에 해당한다.

- 사용자 입력을 받고 ViewModel에게 알린다.

- ViewModel에게서 업데이트될 데이터를 직접 전달받지 않고,

데이터를 관찰하여 데이터가 갱신될 때마다 업데이트하는 방식으로 동작한다.

 

 

✅ ViewModel

 

- View와 Model 사이에서 데이터를 전달하는 역할을 한다.

- View에 데이터를 전달할 때는 직접적으로 전달하지 않는다.

 

 

 


 

LiveData & DataBinding

 

 

위에서 ViewModel이 View에게 데이터를 직접적으로 전달하지 않는다고 여러번 강조하였다.

 

View에서 ViewModel의 데이터를 관찰하고,

데이터가 갱신될 때마다 업데이트 하는 방식을 적용해야 한다.

 

우리는 다음과 같이 2가지의 라이브러리를 통해 MVVM을 적용할 수 있다.

 

 

 

● LiveData

 

Observer가 해당 데이터를 관찰하고 변경 시 변경된 데이터와 함께 알림을 준다.

알림을 받은 시점에서 UI 업데이트를 진행할 수 있다.

 

LiveData에 대한 자세한 내용은 다음 포스팅을 참고하기 바란다.

 

 

[Android] LiveData / MutableLiveData / 라이브 데이터 / 사용법 / 예제

이번 포스팅에서는 라이브 데이터에 대해 알아보자. 라이브 데이터란? 공식 문서 ↓ LiveData 개요 | Android 개발자 | Android Developers LiveData를 사용하여 수명 주기를 인식하는 방식으로 데이터를 처리

oscarstory.tistory.com

 

 

 

 

● DataBinding

 

데이터와 View를 결합하여 데이터가 바뀔 때마다 View에 자동 적용한다.

 

DataBinding에 대한 자세한 내용은 다음 포스팅을 참고하기 바란다.

 

 

[Android] 데이터 바인딩 / DataBinding / 사용법 / 예제

이번엔 데이터 바인딩에 대해 알아보자. 데이터 바인딩이란? 공식 문서 ↓ 데이터 결합 라이브러리 | Android 개발자 | Android Developers 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를

oscarstory.tistory.com

 

 

 

 


 

예제

 

 

위에서 언급한 2가지 방법으로 MVVM을 적용해볼 것인데,

Model과 ViewModel은 동일한 코드를 사용할 것이기에 먼저 보겠다.

 

 

🟢 Model.java

public class Model {

    String work;

    public String choiceWork() {

        Random random = new Random();
        int num = random.nextInt(5);

        switch (num) {

            case 0 : work = "프로젝트 작업";
                break;

            ...

        }

        return work;

    }

}

 

 

Model은 ViewModel의 호출을 받아 간단한 랜덤 로직을 동작시키고

work라는 데이터를 정제하여 반환하는 역할을 한다.

 

 


 

 

🟢 ViewModel.java

public class ViewModel extends ViewModel {

    Model model = new Model();
    MutableLiveData<String> _work = new MutableLiveData<>();

    public LiveData<String> getWork() {
        return _work;
    }

    public void setWork() {
        _work.setValue(model.choiceWork());
    }

}

 

 

ViewModel에서는 Model을 참조해주고, LiveData를 관리한다.

 

Activity에서 setWork() 메서드를 호출하면,

ViewModel에서는 Model의 choiceWork() 메서드를 호출하여

work 데이터를 반환받고 LiveData에 setValue() 해준다.

 

View를 참조하여 UI를 업데이트 시켜주는 부분은 없다.

 

 


 

 

✅ LiveData 활용

 

 

MainActivity부터 2가지 방식으로 나뉜다.

 

먼저 LiveData만 활용한 방법이다.

 

 

🟢 MainActivity

public class MainAcitivy extends AppCompatActivity {

    ViewModel viewModel;
    TextView textView;
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewModel = new ViewModel();
        textView = findViewById(R.id.textView);
        button = findViewById(R.id.button);
        
        // ViewModel의 LiveData 관찰하여 UI 업데이트
        viewModel.getWork().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                textView.setText(s);
            }
        });
        
        // 버튼 클릭 시 ViewModel 함수 호출
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                viewModel.setWork();
            }
        });

    }
}

 

 

버튼 클릭 시 ViewModel 함수를 호출하여

ViewModel의 LiveData 값 변경을 유도한다.

 

ViewModel의 LiveData 값이 변경되면 Observer가 인지하고

텍스트뷰의 텍스트를 업데이트 해주는 내용이다.

 

 

 


 

 

✅ LiveData & DataBinding 활용

 

이번엔 2가지 모두 활용한 방법이다.

 

DataBinding을 사용하였기에 레이아웃 파일도 간단하게 올린다.

 

 

🟢 activity_main.xml

<layout>

    <data>

        <variable
            name="viewModel"
            type="com.example.test.ViewModel" />

    </data>

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center"
        >

        <TextView
            android:id="@+id/mvvm2TextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.getWork()}"
            android:gravity="center"
            />

        <Button
            android:id="@+id/mvvm2Button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="랜덤 뽑기"
            android:onClick="@{() -> viewModel.setWork()}"
            />

    </LinearLayout>

</layout>

 

영역 지정이나 글꼴 관련 내용은 모두 삭제했다.

DataBinding을 사용한 부분에만 집중하기 바란다.

 

TextView의 text 속성에 ViewModel.getWork() 데이터를 바인딩했고,

Button의 onClick 속성에서 ViewModel.setWork() 메서드를 실행시켰다.

 

 

 

🟢 MainActivity

public class MainActivity extends AppCompatActivity {

    ActivityMainBinding binding;
    ViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        viewModel = new ViewModel();

        binding.setLifecycleOwner(this);
        binding.setViewModel(viewModel);

    }
}

 

 

앞선 데이터 바인딩 포스팅을 봤다면 이해가 어렵진 않을 것이다.

 

바인딩 클래스를 선언하고, LifecyclerOwner()를 지정하고,

레이아웃 파일에 선언해준 ViewModel 객체를 지정해주면 끝이다.

 

 

앞선 데이터 바인딩 포스팅에서는 데이터 클래스를 바인딩했는데,

이번 예제에서는 ViewModel의 LiveData를 바인딩 해주었다.

 

 

마찬가지로, ViewModel에서 View를 참조하지 않고

UI를 업데이트 시킬 수 있다.

 

 

 


 

 

 

🟢 결과

 

 

2가지 방식의 결과는 동일하기에, 1개의 스크린샷만 올린다.

 

 

 

 

 


 

 

 

이번엔 MVVM 패턴에 대해 알아보았다.

 

 

처음 접한다면 많이 복잡해 보일 것이다.

하지만 사실 MVP 패턴과 사용하는 파일의 개수는 동일하다.

 

View · ViewModel 간의 의존성을 줄이려는 작업을 위해

LiveData · DataBinding 등의 아키텍처를 동반하기 때문에 복잡해 보일 뿐이다.

 

 

의존성을 줄이고 역할 분담을 확실히 해줄수록

책임 소재가 확실하여 유지·보수에 큰 도움이 된다고 느낀다.