CS/Basic

[CS Basic] MVVM Pattern

Bell91 2023. 11. 22. 15:05
반응형

1. MVVM Pattern 이란?

(1) 예시1

MVVM 패턴은 복잡한 앱을 만들기 위해 고안된 방법으로 여러가지 데이터에 대한 대응은 View와 ViewModel은 그대로 있되 Model만 여러가지를 만들어 대응한다. 즉 뷰모델은 그대로 있으며 Model(데이터 형식)만 변경한다.

  • Model 모델 : 데이터 형식을 지정해주는 공간
  • View 뷰 : 유저의 Action을 받아서 처리하는 곳으로 초기 데이터를 뷰모델에 전달해준다. 
  • ViewModel 뷰모델 : 데이터를 저장하는 공간으로 엑티비티가 종료되기 전까지 유지한다.

 

(2) 예시2

  • 사용자 Action이 View를 통해 들어온다.
  • View는 Action 에 맞는 data를 ViewModel에 요청한다.
  • ViewModel은 Model에 데이터를 요청 하고 observable field로 매핑하여 외부로 노출한다.
  • View는 ViewModel을 구독해서 자신을 변경한다.

MVC와 차이점은 Activity를 View로서 사용할 수 있고 ViewModel이 Controller와 같은 역할을 한다는것이다. 그리고 MVVM의 ViewMoedel의 핵심 키워드는 옵저버이다. 옵저버가 뷰모델에서 데이터변경을 감지한뒤 엑티비티로 가져와 View를 업데이트 할 수 있도록 도와준다. 즉 엑티비티 -> 뷰모델의 옵저버가 데이터 변경 감지 -> 뷰변경

  •  

2. CODE

(1) Model

데이터 형식을 지정하는 공간으로 용도에 따라 분류하여 지정한다.

// User 모델
public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

// UserList 모델
public class UserList {
    private List<User> userList;

    public UserList(List<User> userList) {
        this.userList = userList;
    }

    public List<User> getUserList() {
        return userList;
    }
}

 

(2) ViewModel

데이터를 저장하는 공간으로 기본적으로 엑티비티가 종료되기 전, Fragment가 분리되기 전까지 데이터를 유지한다.

 

public class UserListViewModel extends ViewModel {
    private MutableLiveData<List<User>> userList;

    public UserListViewModel() {
        userList = new MutableLiveData<>();
    }

    public LiveData<List<User>> getUserList() {
        return userList;
    }

    public void setUserList(List<User> list) {
        userList.setValue(list);
    }
}

 

(3) View와 연결된 MainActivity

데이터 초기값 저장, 데이터 변경 감지, 유저의 액션을 받는 공간이다.

public class MainActivity extends AppCompatActivity {
    private UserListViewModel userListViewModel;

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

        TextView userListTextView = findViewById(R.id.userListTextView);

        // 뷰모델 초기화
        userListViewModel = new ViewModelProvider(this).get(UserListViewModel.class);

        // 뷰모델에서 데이터 변경 감지
        userListViewModel.getUserList().observe(this, new Observer<List<User>>() {
            @Override
            public void onChanged(List<User> newUserList) {
                // 사용자 목록을 텍스트뷰에 표시
                StringBuilder userListText = new StringBuilder();
                for (User user : newUserList) {
                    userListText.append(user.getName()).append(", ").append(user.getAge()).append(" years\n");
                }
                userListTextView.setText(userListText.toString());
            }
        });

        // 사용자 목록 설정 (예: 어딘가에서 데이터를 받아온다고 가정)
        List<User> sampleUserList = createSampleUserList();
        userListViewModel.setUserList(sampleUserList);
    }

    private List<User> createSampleUserList() {
        // 예시로 사용할 사용자 목록 생성
        return List.of(
                new User("John Doe", 25),
                new User("Jane Smith", 30),
                new User("Bob Johnson", 22)
        );
    }
}

 

3. CODE 2

또다른 예시 코드를 살펴보자

(1) Model

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

 

(2) ViewModel

import androidx.lifecycle.ViewModel;
import androidx.databinding.ObservableField;

public class MainViewModel extends ViewModel {
    public final ObservableField<String> userName = new ObservableField<>();

    public void setUser(User user) {
        userName.set(user.getName());
    }
}

 

(3) View

뷰에서 DataBinding으로 ViewModel에 직접적으로 데이터를 전달한다.

<!-- activity_main.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="viewModel"
            type="com.example.viewmodeldemo.MainViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.userName}"
            android:textSize="18sp"
            android:padding="16dp"
            android:id="@+id/textView" />
    </LinearLayout>
</layout>

 

(4) Activity

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import com.example.viewmodeldemo.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 데이터 바인딩 초기화
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        // ViewModel 초기화
        viewModel = new ViewModelProvider(this).get(MainViewModel.class);

        // 데이터 바인딩과 ViewModel 연결
        binding.setViewModel(viewModel);
        binding.setLifecycleOwner(this);

        // 모델 업데이트
        User user = new User("John Doe");
        viewModel.setUser(user);
    }
}

 


Reference

https://moon-i.tistory.com/entry/Android-%EC%97%90%EC%84%9C-MVC-MVP-MVVM-%EC%98%88%EC%A0%9C%EB%A1%9C-%EA%B3%B5%EB%B6%80%ED%95%98%EA%B8%B0

 

반응형