마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

LiveData 사용방법

0 추천

버튼을 누르면 EeitText의 값을 TextView에 출력합니다.

ViewModel을 적용시켰습니다.(알맞게 한 것인지는 모르겠습니다...)

제가 궁금한 것이 있어서 Log를 찍어봤습니다. 실행하면 Log 1 Log 2 가 출력되고 버튼을 누를 때마다 Log 1가 출력됩니다.

제가 궁금한 거는 버튼을 누를 때마다 아래 문장이 실행되는지가 궁금합니다.

Observer<String> nameObserver;
nameObserver = newName -> nameTextView.setText(newName);

nameViewModel.getCurrentName().observe(this,nameObserver);

Observer라서 상태라서 변화를 감지하면 실행이 되는 거라고 알고 있는데 버튼을 누를 때마다 nameTextView.setText()가 어떻게 실행되는지 궁금합니다.... 

 

Main

public class MainActivity extends AppCompatActivity {
    EditText nameInputView;
    TextView nameTextView;
    Button inputButton;

    NameViewModel nameViewModel;

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

        nameInputView = findViewById(R.id.nameInputView);
        nameTextView = findViewById(R.id.nameTextView);
        inputButton = findViewById(R.id.inputButton);

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

        test();

        inputButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String inputName = nameInputView.getText().toString();
                nameViewModel.getCurrentName().setValue(inputName);
            }
        });
    }
    private void test(){
        Observer<String> nameObserver;
        nameObserver = newName -> nameTextView.setText(newName);
        nameViewModel.getCurrentName().observe(this,nameObserver);
        Log.e("T","2");
    }
}

 

ViewModel

public class NameViewModel extends ViewModel {
    private MutableLiveData<String> currentName;
    public MutableLiveData<String> getCurrentName(){
        if(currentName == null){
            currentName = new MutableLiveData<String>();
        }
        Log.e("T","1");
        return currentName;
    }
}

 

개미1 (1,260 포인트) 님이 2022년 10월 1일 질문

1개의 답변

0 추천

말씀하신 대로 LiveData는 Observer 기법을 사용합니다. 님의 코드에서 test()메소드가ViewModel에 있는 currentName을 observe 하는 코드입니다.

private void test() {
        Observer<String> nameObserver = newName -> nameTextView.setText(newName);
        nameViewModel.getCurrentName().observe(this, nameObserver);
        Log.e("T", "2");
    }



코드를 보시면 observe(this, nameObserver)라고 되어 있습니다. observe의 원형을 문서에서 확인해 보시면 아시겠지만, getCurrentName()에 어떤 변경사항이 생길 때마다  nameObserver 에 있는 onChanged 메소드를 호출하도록 되어 있습니다.

https://developer.android.com/reference/androidx/lifecycle/LiveData
https://developer.android.com/reference/androidx/lifecycle/Observer
 

abstract void onChanged(T t)


참고로
 

Observer<String> nameObserver = newName -> nameTextView.setText(newName);



위의 코드는 lambda expression으로 아래와 같이 길게 되어 있던 코드를 위처럼 간단하게 바꾼 겁니다.

Observer<String> nameObserver = new Observer<>() {
        @Override
        public void onChanged(String newName) {
            nameTextView.setText(newName);
        }
    }

람다식은 인터페이스의 메소드가 한개만 존재할 때, 인터페이스의 인스턴스 생성 부분과 메소드의 이름부를 생략하고 메소드 부분만 적을 수 있도록 해줌

nameObserver를 인라인으로 만들어 보면 아래와 같습니다.
 

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



따라서 위의 코드는 "nameViewModel의 currentName이 변경이 있을 때마다 onChange메소드에 있는 코드, 즉, nameTextView에 새로운 이름을 표시하겠다"로 읽을 수 있습니다.

그리고 nameViewModel의 currentName의 변경은 아래의 코드가 시작하고 있습니다.
 

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

따라서 버튼을 누를 때마 NameViewModel에 있는 LiveData인 currentName이 변경이 되므로, 이걸 observe하고 있는 nameObserver.onChange 메소드가 실행되게 되는 것입니다.

이해가 가시나요?

참고로, 한가지 신경쓰셨으면 하는 부분이 있어서 말씀드립니다.
 

public class NameViewModel extends ViewModel { 
   ... 
   public LiveData<String> getCurrentName(){ ... } 
}


ViewModel에서 LiveData를 외부에 공개할 때는 멤버필드에 바로 접근할 수 없도록 해주어야 합니다. MutableLiveData를 public으로 만들경우, 아래처럼,
 

nameViewModel.getCurrentName().setValue(inputName);


뷰에서 LiveData를 직접 수정하게 됩니다. 이건 OOP의 기본원칙인 encapsulation을 깨뜨리게 되므로 LiveData타입으로 읽기전용을 만들어 주시고 LiveData의 변경은 별도의 메소드를 공개하여 처리하는 것을 권장합니다.
 

public class NameViewModel extends ViewModel { ...

    private MutableLiveData<String> currentName = new MutableLiveData<>(); 
    public LiveData<String> getCurrentName() {
          return currentName;
    }

    public void onNameChanged(String name) {
        currenName.postValue(name);
    }
} 



도움이 되시길.

spark (227,530 포인트) 님이 2022년 10월 1일 답변
spark님이 2022년 10월 2일 수정
...