/Mvvm-Sample

This repo is done to understand MVVM architecture

Primary LanguageKotlin

💣 Mvvm Sample 💦

🧡 Basic Calculator 💗

class MainActivity : AppCompatActivity(), View.OnClickListener {
    private lateinit var binding: ActivityMainBinding
    private var numberOne: Int? = null
    private var numberTwo: Int? = null
    private var result: Int? = null

    companion object {
        private var isCheck: Boolean = true
    }

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

        binding.btnSum.setOnClickListener(this)
        binding.btnSub.setOnClickListener(this)
        binding.btnMulti.setOnClickListener(this)
        binding.btnDiv.setOnClickListener(this)
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.change_theme_menu, menu)
        return super.onCreateOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.changeTheme -> changeTheme()
        }
        Log.v("ChangeTheme", isCheck.toString())
        return super.onOptionsItemSelected(item)
    }

    override fun onClick(view: View?) {
        when (view?.id) {
            R.id.btnSum -> sumNumbers()
            R.id.btnSub -> subNumbers()
            R.id.btnMulti -> multiNumbers()
            R.id.btnDiv -> divNumbers()
        }
    }

    private fun sumNumbers() {
        numberOne = binding.editNumber1.text.toString().toIntOrNull()
        numberTwo = binding.editNumber2.text.toString().toIntOrNull()
        if (numberOne == null || numberTwo == null) {
            Toast.makeText(this, "Enter Numbers!!!", Toast.LENGTH_SHORT).show()
        } else {
            result = (numberOne!! + numberTwo!!)
            binding.textResult.text = result.toString()
        }
    }

    private fun changeTheme() {
        isCheck = if (isCheck) {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
            false
        } else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
            true
        }
    }
}

🔥 Notes

  • isCheck should be static. İf yo don't put this value static, you should click change theme part twice.
  • I define these variable in main activity. So You don't need define these again in functions.
  • Static variables are created as soon as the project starts running and continue to run until the program terminates.The situation is different when creating the object. Occurs when the object is called and then it is deleted by garbage collector.
  • ‼️ Static variables are not suitable for object oriented programming. Also it increases addictions.

🧡 Calculator with View Model 💗

class MainActivity : AppCompatActivity(), View.OnClickListener {
    private lateinit var binding: ActivityMainBinding
    private val viewModel: MainViewModel by viewModels()
    private var number1: Int? = null
    private var number2: Int? = null
    private lateinit var toastMessage: String

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        
        toastMessage = "Enter Numbers!!!"
        binding.textResult.text = viewModel.result

        binding.btnSum.setOnClickListener(this)
        binding.btnSub.setOnClickListener(this)
        binding.btnMulti.setOnClickListener(this)
        binding.btnDiv.setOnClickListener(this)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.change_theme_menu, menu)
        return super.onCreateOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.changeTheme -> changeTheme()
        }
        return super.onOptionsItemSelected(item)
    }

    override fun onClick(view: View?) {
        when (view?.id) {
            R.id.btnSum -> sumNumbers()
            R.id.btnSub -> subNumbers()
            R.id.btnMulti -> multiNumbers()
            R.id.btnDiv -> divNumbers()
        }
    }

    private fun sumNumbers() {
        number1 = binding.editNumber1.text.toString().toIntOrNull()
        number2 = binding.editNumber2.text.toString().toIntOrNull()
        if (number1 == null || number2 == null) {
            Toast.makeText(this, toastMessage, Toast.LENGTH_SHORT).show()
        } else {
            viewModel.sum(number1.toString(), number2.toString())
            binding.textResult.text = viewModel.result
        }
    }

    private fun changeTheme() {
        viewModel.checkThem()
    }
}

class MainViewModel:ViewModel() {
    var result = "0"
    
    companion object{
        var isCheck:Boolean = true
    }

    fun sum(number1:String,number2:String){
        val num1 = number1.toInt()
        val num2 = number2.toInt()
        val sum = num1 +num2
        result = sum.toString()
    }


    fun checkThem(){
        isCheck = if (isCheck) {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
            false
        } else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
            true
        }
    }
}


🔥Notes

  • ViewModel class should inherit ViewModel() class.
  • General operations are done in the view model, then these operations are called from MainActivity

🧡 Calculator with Live Data 💗

class MainActivity : AppCompatActivity(), View.OnClickListener {
    private lateinit var binding: ActivityMainBinding
    private val viewModel: MainViewModel by viewModels()
    private var number1: Int? = null
    private var number2: Int? = null
    private lateinit var toastMessage: String


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

        toastMessage = "Enter Numbers!!!"

        viewModel.result.observe(this) {
            binding.textResult.text = it
        }

        binding.btnSum.setOnClickListener(this)
        binding.btnSub.setOnClickListener(this)
        binding.btnMulti.setOnClickListener(this)
        binding.btnDiv.setOnClickListener(this)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.change_theme_menu, menu)
        return super.onCreateOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.changeTheme -> changeTheme()
        }
        return super.onOptionsItemSelected(item)
    }

    override fun onClick(view: View?) {
        when (view?.id) {
            R.id.btnSum -> sumNumbers()
            R.id.btnSub -> subNumbers()
            R.id.btnMulti -> multiNumbers()
            R.id.btnDiv -> divNumbers()
        }
    }

    private fun sumNumbers() {
        number1 = binding.editNumber1.text.toString().toIntOrNull()
        number2 = binding.editNumber2.text.toString().toIntOrNull()
        if (number1 == null || number2 == null) {
            Toast.makeText(this, toastMessage, Toast.LENGTH_SHORT).show()
        } else {
            viewModel.sum(number1.toString(), number2.toString())
        }
    }

    private fun changeTheme() {
        viewModel.checkThem()
    }
}
class MainViewModel:ViewModel() {
    var result = MutableLiveData<String>()
    var isCheck =MutableLiveData<Boolean>()

    init {
        isCheck = MutableLiveData<Boolean>(true)
    }

    fun sum(number1:String,number2:String){
        val num1 = number1.toInt()
        val num2 = number2.toInt()
        val sum = num1 +num2
        result.value= sum.toString()
    }

    fun checkThem(){
        isCheck.value= if (isCheck.value==true) {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
            false
        } else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
            true
        }
    }
}

🔥 Notes

What is the difference between LiveData and MutableLiveData?

  • LiveData is immutable while MutableLiveData is mutable. So we can observe and set the values using postValue() and setValue() methods in MutableLiveData. Namely when you don't want your data to be modified use LiveData If you want to modify your data later use MutableLiveData.
  • MutableLİveData is a subclass of LiveData.
  • In init function, you can initialize these values.
  • Cause you are using live data, you can observe this data
  • In here, you start to use .value

🧡 Calculator with Repo 💗

class MainActivity : AppCompatActivity(), View.OnClickListener {
    private lateinit var binding: ActivityMainBinding
    private val viewModel: MainViewModel by viewModels()
    private var numberOne: Int? = null
    private var numberTwo: Int? = null

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

        viewModel.result.observe(this) {
            binding.textResult.text = it
        }

        binding.btnSum.setOnClickListener(this)
        binding.btnSub.setOnClickListener(this)
        binding.btnMulti.setOnClickListener(this)
        binding.btnDiv.setOnClickListener(this)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.change_theme_menu, menu)
        return super.onCreateOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.changeTheme -> changeTheme()
        }
        return super.onOptionsItemSelected(item)
    }

    override fun onClick(view: View?) {
        when (view?.id) {
            R.id.btnSum -> sumNumbers()
            R.id.btnSub -> subNumbers()
            R.id.btnMulti -> multiNumbers()
            R.id.btnDiv -> divNumbers()
        }
    }

    private fun sumNumbers() {
        numberOne = binding.editNumber1.text.toString().toIntOrNull()
        numberTwo = binding.editNumber2.text.toString().toIntOrNull()
        if (numberOne == null || numberTwo == null) {
            Toast.makeText(this, "Enter Numbers!!!", Toast.LENGTH_SHORT).show()
        } else {
            viewModel.sum(numberOne.toString(), numberTwo.toString())
        }
    }

    private fun changeTheme() {
        viewModel.checkTheme()
    }
}
class MainViewModel : ViewModel() {
    var result = MutableLiveData<String>()
    var isCheck = MutableLiveData<Boolean>()
    var mRepo = Repository()

    init {
        isCheck = mRepo.isCheck
        // result = mRepo.mathResult()
        result = mRepo.mathResult
    }

    fun sum(number1: String, number2: String) {
        mRepo.sumNum(number1, number2)
    }
 
    fun checkTheme() {
        mRepo.checkTheme()
    }
}
class Repository {
    var mathResult = MutableLiveData<String>()
    var isCheck = MutableLiveData<Boolean>()

    init {
        isCheck = MutableLiveData<Boolean>(true)
        mathResult = MutableLiveData<String>("0")
    }

    fun mathResult(): MutableLiveData<String> {
        return mathResult
    }

    fun sumNum(number1: String, number2: String) {
        val num1 = number1.toInt()
        val num2 = number2.toInt()
        val sum = num1 + num2
        mathResult.value = sum.toString()
    }

    fun checkTheme() {
        isCheck.value = if (isCheck.value == true) {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
            false
        } else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
            true
        }
    }
}

🔥 Notes

  • Repo connects with ViewModel, ViewModel connect with (Activity or Fragment)

💗 Output 💗

output