Двухстороннее связывание данных Android: проверено с помощью конвертера - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть эта модель:

class MyViewModel : ViewModel() {
    var unit = "mi"
}

На мой взгляд, я хочу установить флажок, если viewModel.unit == "mi". Это работает:

<layout>
    <data>
        <variable name="viewModel" type="com.example.MyViewModel" />
    </data>

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="@{viewModel.unit.equals(`mi`)}" />
</layout>

Я хочу сделать некоторую причудливую двустороннюю привязку, чтобы при переключении поля свойство в модели представления также изменялось. Поскольку мне нужно конвертировать между Boolean и String, кажется, что конвертер - это правильный инструмент для работы. Вот новое представление:

<layout>
    <data>
        <import type="com.example.Converters" />
        <variable name="viewModel" type="com.example.MyViewModel" />
    </data>

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="@={Converters.convertUnitToChecked(`mi`)}" />
</layout>

Вот преобразователи:

object Converters {

    @InverseMethod("convertCheckedToUnit")
    @JvmStatic
    fun convertUnitToChecked(unit: String): Boolean {
        return unit == "mi"
    }

    @JvmStatic
    fun convertCheckedToUnit(checked: Boolean): String {
        return if (checked) "mi" else "km"
    }
}

Когда я пытаюсь построить это, я получаю ошибку:

error: cannot generate view binders java.lang.IllegalStateException: expression does not support two-way binding
    at android.databinding.tool.expr.Expr.generateInverse(Expr.java:797)
    at android.databinding.tool.expr.MethodCallExpr.generateInverse(MethodCallExpr.java:311)
    at android.databinding.tool.InverseBinding.<init>(InverseBinding.java:65)
    at android.databinding.tool.BindingTarget.addInverseBinding(BindingTarget.java:70)
    at android.databinding.tool.LayoutBinder.<init>(LayoutBinder.java:134)
    at android.databinding.tool.DataBinder.<init>(DataBinder.java:60)
    at android.databinding.tool.CompilerChef.ensureDataBinder(CompilerChef.java:117)
    at android.databinding.tool.CompilerChef.sealModels(CompilerChef.java:369)
    at android.databinding.annotationprocessor.ProcessExpressions.writeResourceBundle(ProcessExpressions.java:244)
    at android.databinding.annotationprocessor.ProcessExpressions.onHandleStep(ProcessExpressions.java:126)
    at android.databinding.annotationprocessor.ProcessDataBinding$ProcessingStep.runStep(ProcessDataBinding.java:247)
    at android.databinding.annotationprocessor.ProcessDataBinding$ProcessingStep.access$000(ProcessDataBinding.java:232)
    at android.databinding.annotationprocessor.ProcessDataBinding.doProcess(ProcessDataBinding.java:113)
    at android.databinding.annotationprocessor.ProcessDataBinding.process(ProcessDataBinding.java:88)
    at org.jetbrains.kotlin.kapt3.base.incremental.IncrementalProcessor.process(incrementalProcessors.kt)
    at org.jetbrains.kotlin.kapt3.base.ProcessorWrapper.process(annotationProcessing.kt:147)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)
    at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)
    at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1068)
    at org.jetbrains.kotlin.kapt3.base.AnnotationProcessingKt.doAnnotationProcessing(annotationProcessing.kt:79)
    at org.jetbrains.kotlin.kapt3.base.AnnotationProcessingKt.doAnnotationProcessing$default(annotationProcessing.kt:35)
    at org.jetbrains.kotlin.kapt3.AbstractKapt3Extension.runAnnotationProcessing(Kapt3Extension.kt:230)
    at org.jetbrains.kotlin.kapt3.AbstractKapt3Extension.analysisCompleted(Kapt3Extension.kt:188)
    at org.jetbrains.kotlin.kapt3.ClasspathBasedKapt3Extension.analysisCompleted(Kapt3Extension.kt:99)
    at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM$analyzeFilesWithJavaIntegration$2.invoke(TopDownAnalyzerFacadeForJVM.kt:96)
    at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:106)
    at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:81)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:555)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:82)
    at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:107)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:546)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:177)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:164)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:54)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:84)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:42)
    at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:104)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1558)
    at sun.reflect.GeneratedMethodAccessor113.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

(Я добавил @JvmStatic аннотацию к конвертерам, потому что без них я получаю еще одну ошибку: cannot find method convertUnitToChecked(java.lang.String).)

Насколько я знаю, мой скрипт сборки содержит все необходимые биты:

apply plugin: 'kotlin-android'                       
apply plugin: 'kotlin-kapt'

android {
    ...
    dataBinding {
        enabled = true
    }
}

dependencies {
    ...
    kapt "com.android.databinding:compiler:$androidGradleVersion"
}

Я не понимаю. Я следовал этим инструкциям к письму. Чего мне не хватает?

...