java - 具有非字符串原始类型的 Android (Kotlin) 双向数据绑定
问题描述
我正在尝试在 Android 中进行 2 向数据绑定(模拟运行 API 级别 29 的 Pixel 3a,最小 API 目标为 21)。我想@={}
在 EditText 的android:text
属性上使用语法。
文档似乎说我们可以使用静态转换器类来转换原始(或可能是复杂的)数据类型,使用注释来描述哪些方法与其他方法相反。我目前正在使用整数,但至少也会使用双打。
从 Int 到字符串的转换方法工作正常。当我的片段布局被膨胀时调用它(尽管奇怪的是,它立即被调用了两次),但是从字符串转换回 int 永远不会被调试器命中。
数据绑定转换器.kt
package com.razelon.svcman.database
import android.widget.EditText
import androidx.databinding.InverseMethod
object DatabindingConverters {
@JvmStatic
@InverseMethod("intToString")
fun stringToInt(v: EditText, old: Int, new: String): Int {
return new.toInt()
}
@JvmStatic
fun intToString(v: EditText, old: Int, new: Int): String {
return new.toString()
}
}
fragment_new_order.xml 的摘录:
<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="viewModel"
type="com.razelon.svcman.orders.FragmentNewOrderViewModel" />
<import type="com.razelon.svcman.database.DatabindingConverters" />
</data>
<ScrollView
android:id="@+id/order_scroller"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarStyle="outsideOverlay">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="48dp">
<EditText
android:id="@+id/edtWorkOrder"
android:layout_width="0dp"
android:layout_height="45dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="16dp"
android:ems="6"
android:hint="@string/hint_work_order"
android:importantForAutofill="no"
android:inputType="number"
// The line in question, for XML
android:text="@={DatabindingConverters.intToString(edtWorkOrder, viewModel.orderNo, viewModel.orderNo)}"
app:layout_constraintBaseline_toBaselineOf="@+id/edtAcct"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/edtAcct" />
// Other views
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</layout>
FragmentNewOrderViewModel.kt
package com.razelon.svcman.orders
import android.app.Application
import androidx.databinding.Bindable
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.razelon.svcman.database.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlin.math.max
const val MAX_WORK_CODES = 5
class FragmentNewOrderViewModel(
val database: SvcDao,
app: Application
) : AndroidViewModel(app) {
private val job = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + job)
private val _listWorkCodes = MutableLiveData<List<WorkCode>>(listOf())
private val _listParts = MutableLiveData<List<SvcPart>>(listOf())
private val _eventResetOrder = MutableLiveData<Boolean>(false)
val serviceMen = database.getAllServiceMen()
val listWorkCodes: LiveData<List<WorkCode>>
get() = _listWorkCodes
val listSvcParts: LiveData<List<SvcPart>>
get() = _listParts
val eventResetOrder: LiveData<Boolean>
get() = _eventResetOrder
val orderNo = MutableLiveData<Int>(0)
fun addWorkCode(): Boolean {
if(_listWorkCodes.value!!.size >= MAX_WORK_CODES) {
return false
}
_listWorkCodes.value = List<WorkCode>(_listWorkCodes.value!!.size + 1) {
if (it < (_listWorkCodes.value!!.size)) {
_listWorkCodes.value?.get(it)!!
} else {
WorkCode(0)
}
}
return true
}
fun updateWorkCode(code: WorkCode) {
}
fun deleteWorkCode(pos: Int) {
_listWorkCodes.value = List<WorkCode>(max(_listWorkCodes.value!!.size - 1, 0)) {
if(it >= pos) _listWorkCodes.value!![it + 1] else _listWorkCodes.value!![it]
}
}
fun addNewPart() {
_listParts.value = List<SvcPart>(_listParts.value!!.size + 1) {
if(it < _listParts.value!!.size) {
_listParts.value!![it]
} else {
SvcPart("", 0.0, 1)
}
}
}
fun deletePart(pos: Int) {
_listParts.value = List<SvcPart>(max(_listParts.value!!.size - 1, 0)) {
if(it >= pos) _listParts.value!![it + 1] else _listParts.value!![it]
}
}
fun resetOrder() {
_eventResetOrder.value = true
_listParts.value = listOf()
_listWorkCodes.value = listOf()
}
fun onOrderReset() {
_eventResetOrder.value = false
}
}
我不知道为什么它不调用@InverseMethod("intToString")
注释标记的逆变器。我object
为类声明使用了关键字,用所需的注释标记了方法,将类型导入到我的布局数据绑定中,并让方法中的参数与文档中的内容相匹配。我是 Kotlin 和 Android 开发的新手,所以我确信它可能是我很容易忽略的东西,但是对于我在这里缺少的东西,任何见解都会受到赞赏。
解决方案
我想通了,这完全是我的错。它没有在帖子中显示,但在我的片段中,我从未真正将布局中的变量分配给我的绑定,因此没有任何东西可以将值发送回。
设置它为我修复了它,因为我之前忘记了它:
FragmentNewOrder.kt
val app = this.activity!!.application
val ds = SvcDatabase.getInstance(app).DAO
val factory = FragmentNewOrderViewModelFactory(ds, app)
val viewModel =
ViewModelProviders.of(this, factory).get(FragmentNewOrderViewModel::class.java)
// Very important, don't forget to bind your data
binding.viewModel = viewModel
推荐阅读
- firebase - Firebase 安全规则。您可以将代码发送给用户吗?
- java - 由于类映射,无法启动 Spring Boot
- flutter - valuenotifier 不会在更改数据时重新呈现小部件
- google-apps-script - 可以使用带有 Google Apps 脚本和 ocrLanguage 参数的 DriveApp 更改 OCR 语言吗?
- python - 如何以周期/视角报告典型空间频率巴特沃斯滤波器的结果?
- recaptcha - 多个站点的 Google 验证码实施
- karate - 将两个 JSON 对象与空手道中混洗的字段和子数组的顺序进行比较
- django-channels - 当同时创建 200 个房间时,django 频道服务器变慢或没有响应
- php - php小修改-数量小计产品页面
- sql - 如何优化删除前 N 条记录后的旧记录?