본문 바로가기
Android/안드로이드 기본지식

안드로이드 ViewModel 사용하기

by 붕어사랑 티스토리 2021. 7. 8.
반응형

ViewModel 이란?

안드로이드 앱에 UI에 관한 정보를 담는 클래스이다

 

 

ViewModel 왜 씀?

내가 스마트폰에서 세로 기준으로 버튼을 누르면 숫자가 올라가는 앱을 만들었다고 하자

그런데 스마트폰을 가로로 돌리면 숫자가 초기화 된다.

 

이유는 간단하다. 가로로 돌리면 액티비티가 파괴되고 처음부터 onCreate를 시작으로 다시 생성되기 때문

이때 ViewModel에 데이터를 저장하면 UI에 관한 데이터를 보존할 수 있다.

 

안드로이드 공식 문서에도 앱을 설계할 때 아래와 같이 ViewModel + LiveData로 UI데이터를 보존하라고 명시하고 있다.

 

 

https://developer.android.com/jetpack/guide?hl=ko 

 

앱 아키텍처 가이드  |  Android 개발자  |  Android Developers

이 가이드에는 고품질의 강력한 앱을 빌드하기 위한 권장사항 및 권장 아키텍처가 포함되어 있습니다. 이 페이지는 Android 프레임워크 기본을 잘 아는 사용자를 대상으로 합니다. Android 앱을 처

developer.android.com

 

 

 

 

 

생명주기를 보자

 

 

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

 

반응형

댓글