在使用Android Databinding和Kotlin的自定义BindingAdapter中使用lambda

我正在尝试使用Kotlin为Android Databinding绑定一个lambda处理程序。 只要我的ViewModel处理程序显式地返回Void就行了。 但是,如果它返回Kotlin单位,我得到一个error: cannot generate view binders java.lang.StackOverflowError

一切似乎都正确地钩上了所有其他自定义绑定工作(convertBooleanToViewVisibility,toTestString,甚至customOnClick只要我打电话onClickVoid [见下面的例子])。

问题是当我试图调用lambda返回单元在我的应用程序:customOnClick而不是返回Void。 在下面的例子中,它是调用mainViewModel.onClick()而不是mainViewModel.onClickVoid() 。 必须有一种方法可以使android:onClick能够调用Unit版本。 但是,如果我使用相同的语法调用onClick的customOnClick,我得到这个错误:

 :app:kaptGenerateStubsDebugKotlin Using kotlin incremental compilation :app:kaptDebugKotlin e: error: cannot generate view binders java.lang.StackOverflowError e: e: at android.databinding.tool.writer.Scope.access$getCurrentScope$cp(LayoutBinderWriter.kt:49) e: at android.databinding.tool.writer.Scope$Companion.getCurrentScope(LayoutBinderWriter.kt:58) e: at android.databinding.tool.writer.LayoutBinderWriterKt.scopedName(LayoutBinderWriter.kt:196) e: at android.databinding.tool.expr.Expr.toCode(Expr.java:776) e: at android.databinding.tool.writer.LayoutBinderWriterKt$callbackLocalName$2.invoke(LayoutBinderWriter.kt:203) e: at android.databinding.tool.writer.LayoutBinderWriterKt$callbackLocalName$2.invoke(LayoutBinderWriter.kt) e: at android.databinding.tool.ext.LazyExt.getValue(ext.kt:27) e: at android.databinding.tool.writer.LayoutBinderWriterKt.getCallbackLocalName(LayoutBinderWriter.kt) e: at android.databinding.tool.writer.LayoutBinderWriterKt.scopedName(LayoutBinderWriter.kt:197) e: java.lang.IllegalStateException: failed to analyze: java.lang.RuntimeException: failure, see logs for details. cannot generate view binders java.lang.StackOverflowError at android.databinding.tool.writer.Scope.access$getCurrentScope$cp(LayoutBinderWriter.kt:49) at android.databinding.tool.writer.Scope$Companion.getCurrentScope(LayoutBinderWriter.kt:58) at android.databinding.tool.writer.LayoutBinderWriterKt.scopedName(LayoutBinderWriter.kt:196) at android.databinding.tool.expr.Expr.toCode(Expr.java:776) at android.databinding.tool.writer.LayoutBinderWriterKt$callbackLocalName$2.invoke(LayoutBinderWriter.kt:203) at android.databinding.tool.writer.LayoutBinderWriterKt$callbackLocalName$2.invoke(LayoutBinderWriter.kt) at android.databinding.tool.ext.LazyExt.getValue(ext.kt:27) at android.databinding.tool.writer.LayoutBinderWriterKt.getCallbackLocalName(LayoutBinderWriter.kt) at android.databinding.tool.writer.LayoutBinderWriterKt.scopedName(LayoutBinderWriter.kt:197) .............................. (TRUNCATED) ................................... at android.databinding.tool.expr.Expr.toCode(Expr.java:776) at android.databinding.tool.writer.LayoutBinderWriterKt$callbackLocalName$2.invoke(LayoutBinderWriter.kt:203) at android.databinding.tool.writer.LayoutBinderWriterKt$callbackLocalName$2.invoke(LayoutBinderWriter.kt) at android.databinding.tool.ext.LazyExt.getValue(ext.kt:27) at android.databinding.tool.writer.LayoutBinderWriterKt.getCallbackLocalName(LayoutBinderWriter.kt) at android.databinding.tool.writer.LayoutBinderWriterKt.scopedName(LayoutBinderWriter.kt:197) at org.jetbrains.kotlin.analyzer.AnalysisResult.throwIfError(AnalysisResult.kt:57) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.kt:144) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:167) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:55) at org.jetbrains.kotlin.cli.common.CLICompiler.exec(CLICompiler.java:182) at org.jetbrains.kotlin.daemon.CompileServiceImpl.execCompiler(CompileServiceImpl.kt:397) at org.jetbrains.kotlin.daemon.CompileServiceImpl.access$execCompiler(CompileServiceImpl.kt:99) at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$2.invoke(CompileServiceImpl.kt:365) at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$2.invoke(CompileServiceImpl.kt:99) at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$2$$special$$inlined$withValidClientOrSessionProxy$lambda$1.invoke(CompileServiceImpl.kt:798) at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$2$$special$$inlined$withValidClientOrSessionProxy$lambda$1.invoke(CompileServiceImpl.kt:99) at org.jetbrains.kotlin.daemon.common.DummyProfiler.withMeasure(PerfUtils.kt:137) at org.jetbrains.kotlin.daemon.CompileServiceImpl.checkedCompile(CompileServiceImpl.kt:825) at org.jetbrains.kotlin.daemon.CompileServiceImpl.access$checkedCompile(CompileServiceImpl.kt:99) at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$2.invoke(CompileServiceImpl.kt:797) at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$2.invoke(CompileServiceImpl.kt:99) at org.jetbrains.kotlin.daemon.CompileServiceImpl.ifAlive(CompileServiceImpl.kt:1004) at org.jetbrains.kotlin.daemon.CompileServiceImpl.ifAlive$default(CompileServiceImpl.kt:865) at org.jetbrains.kotlin.daemon.CompileServiceImpl.doCompile(CompileServiceImpl.kt:791) at org.jetbrains.kotlin.daemon.CompileServiceImpl.access$doCompile(CompileServiceImpl.kt:99) at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1.invoke(CompileServiceImpl.kt:364) at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1.invoke(CompileServiceImpl.kt:99) at org.jetbrains.kotlin.daemon.CompileServiceImpl.ifAlive(CompileServiceImpl.kt:1004) at org.jetbrains.kotlin.daemon.CompileServiceImpl.ifAlive$default(CompileServiceImpl.kt:865) at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:336) at sun.reflect.GeneratedMethodAccessor86.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:324) 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:568) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) ... 39 more FAILED 

任何想法如何使它与单位工作,所以我不需要改变我的ViewModel显式返回Void? 为我所有的处理?

示例项目

项目build.gradle

 buildscript { ext.kotlin_version = '1.1.3-2' ext.plugin_version = '2.3.3' repositories { jcenter() } dependencies { classpath "com.android.tools.build:gradle:$plugin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } allprojects { repositories { jcenter() mavenCentral() } } task clean(type: Delete) { delete rootProject.buildDir } 

模块(应用程序)build.gradle

 buildscript { repositories { jcenter() mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" } } apply plugin: 'com.android.application' apply plugin: "kotlin-android" apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' android { compileSdkVersion 24 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.example.kotlindatabinding" minSdkVersion 24 targetSdkVersion 24 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } dataBinding { enabled = true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main.java.srcDirs += 'src/main/kotlin' } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:26.+' compile 'com.android.support.constraint:constraint-layout:1.0.2' testCompile 'junit:junit:4.12' compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" kapt "com.android.databinding:compiler:$plugin_version" } kapt { generateStubs = true } 

MainActivity.kt

 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) binding.setMainViewModel(MainViewModel()) } } 

MainViewModel.kt

 class MainViewModel { val myName: String get() { return "Hello world!" } fun onClick(){ Log.i("ME", "Logging...") } fun onClickVoid(): Void? { onClick() return null as Void? } } 

Bindings.kt

 object Bindings{ @BindingConversion @JvmStatic fun convertBooleanToViewVisibility(isVisible: Boolean): Int { // Working return if (isVisible) View.VISIBLE else View.GONE } @BindingAdapter("customOnClick") @JvmStatic fun setOnItemClicked(textView: TextView, consumer: (String) -> Any?) { // Working consumer("test") } @JvmStatic fun toTestString(input: Any) : String { return "Test" } } 

activity_main.xml中

 <?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> <import type="com.example.kotlindatabinding.Bindings"/> <variable name="mainViewModel" type="com.example.kotlindatabinding.MainViewModel" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.kotlindatabinding.MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{Bindings.toTestString(mainViewModel.myName)}" android:visibility="@{mainViewModel.myName != null}" android:clickable="true" android:onClick="@{() -> mainViewModel.onClick()}" app:customOnClick="@{(someInput) -> mainViewModel.onClickVoid()}" /> </LinearLayout> </layout> 

将此代码移到默认配置块之外。 把它放进去

 android { dataBinding { enabled = true } }