Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to increment mutablelivedata without additional variable?

I have simple view with edit text and 2 buttons and I want to give user ability to increse/decrese amount by 1 with buttons or he can manually write amount in edit text widget, but this value can't be less than 0 and greater than 10. I'm using MVVM architecture with LiveData and databinding. Currently in ViewModel I've two variables _amount: Int and amount:MutableLiveData. I'm incrmenting/decrementing _amount and then assign new value to MutableLiveData. It's working but I'm wondering if it is possible to achive same result using only one variable to store amount i.e amount:MutableLiveData

ViewModel
class TestActivityVM : ViewModel() {

    val amount = MutableLiveData<String>()
    private var _amount = 0

    init {
        amount.value = _amount.toString()
    }

    fun increment() {
        Log.d("TestActivityVM", "The amount is being increment, current value = ${amount.value}")

        //increment amount value by 1 if amount is less than 10
        if(_amount < 10) {
            amount.value = (++_amount).toString()
        }
    }

    fun decrement() {
        Log.d("TestActivityVM", "The amount is being decrement, current value = ${amount.value}")

        //decrement amount value by 1 if amount is greater than 0
        if(_amount > 0) {
            amount.value = (--_amount).toString()
        }
    }

    val amountValidator: TextWatcher = object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
            _amount = if(s.toString().isEmpty()) 0 else s.toString().toInt()

            if(_amount > 10) {
                _amount = 10
                amount.value = _amount.toString()
            }
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

    }
}
Activity
class TestActivity : AppCompatActivity() {

    private lateinit var testBinding: ActivityTestBinding
    private lateinit var testVM: TestActivityVM

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        testVM = ViewModelProviders.of(this).get(TestActivityVM::class.java)

        testBinding = DataBindingUtil.setContentView<ActivityTestBinding>(this, R.layout.activity_test).also {
            it.lifecycleOwner = this
            it.testVM = testVM
        }
    }
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>

        <variable
            name="testVM"
            type=".TestActivityVM" />
    </data>


    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".TestActivity">

        <Button
            android:id="@+id/minusBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="16dp"
            android:text="-"
            android:onClick="@{() -> testVM.decrement()}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/amountET" />

        <Button
            android:id="@+id/plusBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:layout_marginEnd="8dp"
            android:text="+"
            android:onClick="@{() -> testVM.increment()}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/amountET" />

        <EditText
            android:id="@+id/amountET"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:ems="10"
            android:inputType="numberSigned"
            android:text="@={testVM.amount}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:addTextChangedListener="@{testVM.amountValidator}"/>

        <TextView
            android:id="@+id/textView4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="84dp"
            android:text="Value of amount Live data:"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/minusBtn" />

        <TextView
            android:id="@+id/textView5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="32dp"
            android:layout_marginTop="8dp"
            android:text="@{testVM.amount}"
            android:textSize="24sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView4" />

    </android.support.constraint.ConstraintLayout>
</layout>

like image 597
Remzo Avatar asked Jul 26 '19 12:07

Remzo


1 Answers

You can use amount.value to get the current amount, instead of using another variable. The LiveData should be of Int, not String, as that's the data type you're dealing with. Here's how your code could look like:

class TestActivityVM : ViewModel() {

    val amount = MutableLiveData<Int>().apply {
        value = 0
    }

    fun increment() {
        Log.d("TestActivityVM", "The amount is being increment, current value = ${amount.value}")

        //increment amount value by 1 if amount is less than 10
        amount.value?.let { a ->
            if (a < 10) {
                amount.value = a + 1
            }
        }
    }
like image 104
cd1 Avatar answered Nov 15 '22 07:11

cd1