ViewModel 이란?
안드로이드 앱에 UI에 관한 정보를 담는 클래스이다
ViewModel 왜 씀?
내가 스마트폰에서 세로 기준으로 버튼을 누르면 숫자가 올라가는 앱을 만들었다고 하자
그런데 스마트폰을 가로로 돌리면 숫자가 초기화 된다.
이유는 간단하다. 가로로 돌리면 액티비티가 파괴되고 처음부터 onCreate를 시작으로 다시 생성되기 때문
이때 ViewModel에 데이터를 저장하면 UI에 관한 데이터를 보존할 수 있다.
안드로이드 공식 문서에도 앱을 설계할 때 아래와 같이 ViewModel + LiveData로 UI데이터를 보존하라고 명시하고 있다.
https://developer.android.com/jetpack/guide?hl=ko
생명주기를 보자
ViewModel에 데이터를 저장하면 앱의 라이프사이클 거의 모든 사이클 전반에 걸쳐 살아남는다.
ViewModel 어떻게 씀?
1. ViewModel 클래스를 상속받아 ViewModel을 만드셈. ViewModel안에 UI데이터를 넣는데 이걸 Model 이라고 하자
2. Activity에서 ViewModelProvider를 생성한 후에 ViewModel을 생성하면 됨
3. ViewModel을 생성했으면 ViewModel에서 UI데이터를 꺼내서 마음껏 쓰면됨
예제좀
물고기를 출력해주는 앱을 만들거임.
붕어(25살) 메기(31살) 광어(20살) 을 버튼으로 누르면 출력해주는 앱임
ViewModel을 쓰지 않으면 생기는 문제점?
자 ui에서 내가 Megi를 출력했다고 치자. 그런데 화면을 가로로 회전하면?
아래처럼 Bounga로 초기화 되버림. 왜냐하면 화면을 회전할 때 액티비티를 destroy 하고 처음부터 다시 시작하기 때문!
ViewModel을 쓰면 어떻게됨?
패키지 구조
레이아웃 만들기
레이아웃 만들때 가로모드에 대한 layout을 만들어 줘야함
activity_main.xml에 들어가서 저기 회전버튼을 누르면 create landscape variation이라는게 있음
그걸 누루면 알아서 가로모드 xml을 하나 만들어줌
폴더구조도 위와같이 바뀜
layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/nameTextView"
style="@style/TextAppearance.MaterialComponents.Headline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Bounga" />
<TextView
android:id="@+id/ageTextView"
style="@style/TextAppearance.MaterialComponents.Headline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="25" />
</LinearLayout>
<Button
android:id="@+id/prevButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_margin="8dp"
android:text="@string/prev"
tools:ignore="ButtonStyle" />
<Button
android:id="@+id/nextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="8dp"
android:text="@string/next"
tools:ignore="ButtonStyle" />
</FrameLayout>
land/activity_main.xml (가로모드용)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/nameTextView"
style="@style/TextAppearance.MaterialComponents.Headline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Bounga" />
<TextView
android:id="@+id/ageTextView"
style="@style/TextAppearance.MaterialComponents.Headline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="25" />
</LinearLayout>
<Button
android:id="@+id/prevButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_margin="8dp"
android:text="@string/prev"
tools:ignore="ButtonStyle" />
<Button
android:id="@+id/nextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="8dp"
android:text="@string/next"
tools:ignore="ButtonStyle" />
</FrameLayout>
Fish.java
public class Fish {
private String name;
private int age;
public Fish(String name, int age){
this.name = name;
this.age = age;
}
public String getNameOfFish(){
return this.name;
}
public int getAgeOfFish(){
return this.age;
}
}
FishViewModel.java
public class FishViewModel extends ViewModel {
List<Fish> fishes = Arrays.asList(
new Fish("Bounga",25),
new Fish("Megi",31),
new Fish("GwangUh",20)
);
private int currentIndex = 0;
public Fish getCurrentFish(){
return fishes.get(currentIndex);
}
public int getCurrentIndex(){
return this.currentIndex;
}
public void setCurrentIndex(int idx){
currentIndex = idx;
if(currentIndex >= fishes.size()){
currentIndex = fishes.size()-1;
}
if(currentIndex<0)currentIndex = 0;
}
public void next(){
currentIndex += 1;
if(currentIndex >= fishes.size()) currentIndex = 0;
}
public void prev(){
currentIndex-=1;
if(currentIndex<0)currentIndex = 0;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private TextView nameTextView;
private TextView ageTextView;
private FishViewModel fishViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewModelProvider provider = new ViewModelProvider(this);
fishViewModel = provider.get(FishViewModel.class);
nameTextView = findViewById(R.id.nameTextView);
ageTextView = findViewById(R.id.ageTextView);
Button prevButton = findViewById(R.id.prevButton);
Button nextButton = findViewById(R.id.nextButton);
prevButton.setOnClickListener(this::onPrev);
nextButton.setOnClickListener(this::onNext);
update();
}
public void update(){
Fish fish = fishViewModel.getCurrentFish();
nameTextView.setText(fish.getNameOfFish());
ageTextView.setText(
MessageFormat.format("{0}",fish.getAgeOfFish())
);
}
private void onPrev(View view){
fishViewModel.prev();
update();
}
private void onNext(View view){
fishViewModel.next();
update();
}
}
ViewModel 생명 주기좀
출저 : https://developer.android.com/topic/libraries/architecture/viewmodel?hl=ko
'Android > 안드로이드 기본지식' 카테고리의 다른 글
안드로이드 inflate, inflater란? (0) | 2021.07.19 |
---|---|
안드로이드 onSaveInstanceState (0) | 2021.07.08 |
안드로이드 LiveData 기본예제 (2) | 2021.07.01 |
안드로이드 Fragment 사용하기 (0) | 2021.06.30 |
[Android] kotlin에서 안드로이드 Fragment 제거하기 (0) | 2021.06.14 |
댓글