본문 바로가기

안드로이드

안드로이드 LiveData 사용 방법(ViewModel)

안녕하세요 

이번 시간에는 LiveData에 대해 알아보겠습니다.

 

LiveData는 Observer기법을 사용합니다.

LiveData는 관찰 가능한 데이터 홀더 클래스입니다.

쉽게 말해서 Observer가 LiveData를 관찰하고 있으며 변화가 있을 때 onChanged 이벤트를 발생시킵니다.

 

LiveData는 읽을 수 있지만 변경할 수는 없습니다.

데이터를 변경하고 싶으면 MutableLiveData를 이용해야 합니다.

 

이름에서 알 수 있듯이 MutableLiveData는 데이터를 변경할 수 있습니다. ViewModel 내부에서 데이터는 편집 가능해야 하므로 MutableLiveData 를 사용합니다.

ViewModel 외부에서 데이터를 읽을 수 있지만 편집은 불가능합니다. 그래서 외부에 보여지는 데이터는 LiveData를 이용해야 합니다. 

외부에서 데이터를 변경하면 OOP의 기본원칙인 encapsulation을 깨뜨리게 되므로 LiveData는 읽기 전용을 만들어야 하고  MutableLiveData의 변경은 별도의 메소드를 공개하여 처리하는 것을 권장한다고 합니다.

 

 

코드를 보면서 설명을 이어나가겠습니다.

 

우선 화면 구성부터 해봅시다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/nameInput"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="textPersonName"
            android:text="Name" />

        <Button
            android:id="@+id/inputButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:text="Button" />
    </LinearLayout>

    <TextView
        android:id="@+id/nameText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TextView" />
</LinearLayout>

 

 

Main

public class MainActivity extends AppCompatActivity {
    EditText nameInput;
    TextView nameText;
    Button inputButton;

    NameViewModel nameViewModel;

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

        nameInput = findViewById(R.id.nameInput);
        nameText = findViewById(R.id.nameText);
        inputButton = findViewById(R.id.inputButton);

        //ViewModel 생성
        nameViewModel = new ViewModelProvider(this)
                .get(NameViewModel.class);

        //옵저버 정의 데이터가 변하는 이벤트 발생시 처리할 핸들러
        Observer<String> nameObserver = newName -> nameText.setText(newName);
        
        //ViewModel에 옵저버 등록
        nameViewModel.getCurrentName().observe(this,nameObserver);
        
        inputButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String inputName = nameInput.getText().toString();
                nameViewModel.onNameChanged(inputName);
            }
        });
    }
}

 

ViewModel

public class NameViewModel extends ViewModel {
    private MutableLiveData<String> currentName;
    public LiveData<String> getCurrentName(){
        if(currentName == null){
            currentName = new MutableLiveData<String>();
        }
        return currentName;
    }
    public void onNameChanged(String name) {
        currentName.postValue(name);
    }
}

 

참고로 ViewModel의 생명주기는 onCreate()부터 onDestroy()까지 입니다.

ViewModel을 사용하는 이유는 생명주기에 영향을 받지 않기 때문입니다.

여러분 혹시 핸드폰은 가로로 돌리면 데이터가 초기화되는 현상 경험해 보신 적 있나요?

화면이 돌아가면서 다시 onCreate()부터 시작되기 때문에 초기화된 것입니다.

ViewModel을 사용하면 이러한 걱정은 없겠죠?

 

코드를 설명드리겠습니다.

	Observer<String> nameObserver = newName -> nameTextView.setText(newName);
        nameViewModel.getCurrentName().observe(this, nameObserver);

ViewModel에 getCurrentName()에 변경이 있을 때마다 nameObserver에 있는 onChanged메소드를 호출하겠다는 의미입니다.

그러나 onChanged가 보이지 않죠?

 

위에 코드는 아래와 같은 내용입니다.

 Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(String newName) {
                nameText.setText(newName);
            }
        };
nameViewModel.getCurrentName().observe(this,nameObserver);

 

 

 

public class NameViewModel extends ViewModel {
    private MutableLiveData<String> currentName;
    public LiveData<String> getCurrentName(){
        if(currentName == null){
            currentName = new MutableLiveData<String>();
        }
        return currentName;
    }
    public void onNameChanged(String name) {
        currentName.postValue(name);
    }
}

 

초반에 설명드렸다시피MutableLiveData와 LiveData를 나누어 주었습니다.

외부에서 읽기 전용으로 사용할  LiveData입니다. 

내부에서 편집을 할 수 있는 MutableLiveData 입니다.

 

 

inputButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String inputName = nameInput.getText().toString();
                nameViewModel.onNameChanged(inputName);
            }
        });

메인에서 버튼을 누르면 MutableLiveData의 currentName이 변경됩니다.

내부에서 MutableLiveData로 데이터를 편집했습니다. 이후 Observer가 변화를 감지하여 LiveData를 읽었습니다.

 

수고하셨습니다

다음 시간에는 RxJava에 관한 내용을 업로드하겠습니다.

 

 

 

반응형