Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

둘 모두 하나의 TextView에 보여질 예정이므로 String LiveData를 하나 준비합니다.

Code Block
private val _text = MutableLiveData("")
val text: LiveData<String>
    get() = _text

수식은 계속해서 더해지고 지워져야 하므로 저장할 변수가 필요합니다.
계산 결과는 계산이 완료되었을 때 바로 String LiveData로 보여주면 되므로 저장할 변수가 필요하지 않습니다.


Code Block
private var expression = Expression.EMPTY

View에서 ViewModel에 전달할 이벤트

레이아웃 xml 또는 Activity, Fragment에서 ViewModel의 함수를 호출하여 유저가 발생시킨 이벤트를 전달해야 합니다.

Code Block
class MainViewModel : ViewModel() {
    fun addToExpression(operand: Int) { ... }

    fun addToExpression(operator: Operator) { ... }    

    fun removeLast() { ... }

    fun calculate() { ... }
}

xml에서 데이터바인딩 처리

Code Block
<layout>
    <data>

        <import type="edu.nextstep.camp.calculator.domain.Operator" />

        <variable
            name="viewModel"
            type="edu.nextstep.camp.calculator.MainViewModel"
            />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout>
         <TextView
            android:id="@+id/textView"
            android:text="@{viewModel.text}"
            />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/buttonDelete"
            android:onClick="@{() -> viewModel.removeLast()}"
            />

        <GridLayout>
            <Button
                android:id="@+id/button0"
                android:onClick="@{() -> viewModel.addToExpression(0)}"
                />
            <!-- 1 ~ 9 버튼 생략 -->

            <Button
                android:id="@+id/buttonPlus"
                android:onClick="@{() -> viewModel.addToExpression(Operator.Plus)}"
                />
            <!-- Minus, Multiply, Divide 생략 -->

            <Button
                android:id="@+id/buttonEquals"
                android:onClick="@{() -> viewModel.calculate()}"
                />
        </GridLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Activity에서 데이터바인딩 클래스 사용

데이터바인딩을 통해 레이아웃 xml 파일을 토대로 XxxBinding 클래스가 자동 생성됩니다.
여기서는 activity_main.xml 파일에 해당하는 ActivityMainBinding 클래스가 해당됩니다.

Code Block
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val viewModel: MainViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.lifecycleOwner = this
        binding.viewModel = viewModel
    }
}

ViewModel에서 발생한 이벤트를 View에서 처리

= 버튼을 눌렀을 때 수식이 완성되어 있으면 계산이 수행됩니다. 
하지만 수식이 미완성 상태이면 ViewModel에서 계산을 할 수 없다는 이벤트를 View에 전달하여 View에서 사용자에게 에러가 발생했음을 알려주어야 합니다.

Code Block
class MainViewModel : ViewModel() {
    private val _onCalculationErrorEvent = MutableLiveData<Unit>()
    val onCalculationErrorEvent: LiveData<Unit>
        get() = _onCalculationErrorEvent
}

...


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        viewModel.onCalculationErrorEvent.observe(this) {
            Toast.makeText(this, R.string.incomplete_expression, Toast.LENGTH_SHORT).show()
        }
    }
}