首页 > 解决方案 > 如何将业务逻辑赋予 ViewModel Kotlin?

问题描述

作为一名学生,我正在从事一个培训项目,但我不知道如何将我的业务逻辑NewItemActivityNewItemViewModel. 事实证明,我拥有在片段内验证和创建 ItemModel 的所有逻辑。这样做不好,这些都是业务逻辑中需要交给viewModel的部分。如何将业务逻辑转移到 ViewModel,但同时保持应用程序正常工作?否则我试过了,一切都为我打破了。

新项目活动.kt

class NewItemActivity : AppCompatActivity() {

    private val calendar: Calendar = Calendar.getInstance()
    private val viewModel: NewItemViewModel by viewModels(factoryProducer = {
        NewItemViewModel.Factory()
    })

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_new_item)

        val saveButton = findViewById<Button>(R.id.saveButton)
        val editDate = findViewById<EditText>(R.id.editDate)

        val date = SimpleDateFormat("dd.MM.yyyy")
        val dateDefault = date.format(calendar.timeInMillis)
        editDate.setText(dateDefault)

        editDate.setOnClickListener {
            showDatePickerDialog()
        }

        saveButton.setOnClickListener {
            checkStateDescriptionLayout()

            if (checkStateTitleLayout()) return@setOnClickListener
            if (checkStateDescriptionLayout()) return@setOnClickListener

            val newItem = ItemModel(
                title = editTitle.text.toString(),
                description = editDescription.text.toString(),
                date = Date(),
                isFavorite = false
            )

            viewModel.saveNewItem(newItem)

            Toast.makeText(this, "New item added", Toast.LENGTH_SHORT).show()
            finish()
        }

        textChangedListener()
    }

    private fun showDatePickerDialog() {
        val datePickerDialog = DatePickerDialog(
            this@NewItemActivity,
            { _, year, monthOfYear, dayOfMonth ->
                val selectedDate: String =
                    dayOfMonth.toString() + "." + (monthOfYear + 1) + "." + year
                editDate?.setText(selectedDate)
            },
            calendar.get(Calendar.YEAR),
            calendar.get(Calendar.MONTH),
            calendar.get(Calendar.DAY_OF_MONTH)
        )
        datePickerDialog.datePicker.maxDate = calendar.timeInMillis
        datePickerDialog.show()
    }

    private fun checkStateTitleLayout(): Boolean {
        val titleLayout = findViewById<TextInputLayout>(R.id.editTitleLayout)
        val checkTitleLayoutState = titleLayout.editText?.text?.toString()
        val fieldIsRequired = getString(R.string.fieldIsRequired)

        val error: Boolean = checkTitleLayoutState!!.isEmpty()
        if (error) titleLayout.error = fieldIsRequired

        return error
    }

    private fun checkStateDescriptionLayout(): Boolean {
        val descriptionLayout = findViewById<TextInputLayout>(R.id.editDescriptionLayout)
        val checkDescriptionLayoutState = descriptionLayout.editText?.text?.toString()
        val fieldIsRequired = getString(R.string.fieldIsRequired)

        val error: Boolean = checkDescriptionLayoutState!!.isEmpty()
        if (error) descriptionLayout.error = fieldIsRequired

        return error
    }

    private fun textChangedListener() {
        val titleLayout = findViewById<TextInputLayout>(R.id.editTitleLayout)
        val descriptionLayout = findViewById<TextInputLayout>(R.id.editDescriptionLayout)

        titleLayout.editText?.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            override fun afterTextChanged(s: Editable?) {
                titleLayout.error = null
                titleLayout.isErrorEnabled = false
            }
        })

        descriptionLayout.editText?.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            override fun afterTextChanged(s: Editable?) {
                descriptionLayout.error = null
                descriptionLayout.isErrorEnabled = false
            }
        })
    }
}

新项目视图模型.kt

class NewItemViewModel(
    private val repository: MyItemsRepository
) : ViewModel() {

    fun saveNewItem(item: ItemModel) = repository.saveNewItem(item)

    class Factory : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return NewItemViewModel(MyItemsRepositoryImpl.getInstance()) as T
        }
    }
}

标签: androidkotlinfragmentandroid-viewmodel

解决方案


似乎您的主要业务逻辑包含在 onCreate 中,当您的业务逻辑很少时,这不是一个大问题,而且您的逻辑基本上是一个事件(保存 ItemModel 对象)。

如果您仍想将更多逻辑移至 ViewModel,请将 ItemModel 的创建移至 ViewModel 并提供函数以更改 ItemModel 的每个参数。它应该如下所示:

class NewItemViewModel(
    private val repository: MyItemsRepository
) : ViewModel() {

    private var title = ""
    private var description = ""
    private var date = Date()
    private var isFavorite = false

    fun setTitle(s: String) { title = s }
    fun setDescription(s: String) { description = s }
    fun setDate(d: Date) { date = d }
    fun setIsFavorite(b: Boolean) { isFavorite = b }
    fun saveNewItem() = repository.saveNewItem(Item(title, description, date, isFavorite))

    class Factory : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return NewItemViewModel(MyItemsRepositoryImpl.getInstance()) as T
        }
    }
}

你可能认为这比它的价值更麻烦,你是对的。但是,为更复杂的逻辑做准备是没有害处的;)

PS我没有测试过这段代码,但应该基本正确。


推荐阅读