如何在xml布局上使用随播对象?

时间:2018-06-20 14:07:57

标签: android kotlin android-databinding

我正在尝试在布局内使用伴随对象属性,但编译器无法识别它。

科林班

class MyClass {
  companion object {
    val SomeProperty = "hey"
  }
}

XML布局

<layout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:fancy="http://schemas.android.com/tools">

  <data>
    <import type="package.MyClass"/>
  </data>

  <TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="@{MyClass.Companion.SomeProperty}"/>

</layout>

我得到了这个错误:

e: java.lang.IllegalStateException: failed to analyze: android.databinding.tool.util.LoggedErrorException: Found data binding errors.
****/ data binding error ****msg:Could not find accessor package.MyClass.Companion.SomeProperty file:/path/to/my/layout.xml loc:21:67 - 21:103 ****\ data binding error ****

    at org.jetbrains.kotlin.analyzer.AnalysisResult.throwIfError(AnalysisResult.kt:57)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.kt:138)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:154)
    ...
Caused by: android.databinding.tool.util.LoggedErrorException: Found data binding errors.
****/ data binding error ****msg:Could not find accessor package.MyClass.Companion.SomeProperty file:/path/to/my/layout.xml loc:21:67 - 21:103 ****\ data binding error ****

    at android.databinding.tool.processing.Scope.assertNoError(Scope.java:112)
    at android.databinding.annotationprocessor.ProcessDataBinding.doProcess(ProcessDataBinding.java:101)
    at android.databinding.annotationprocessor.ProcessDataBinding.process(ProcessDataBinding.java:65)
    ...

我尝试使用companion代替Companion,但是没有运气。

是否可以在具有数据绑定的xml布局上使用伴随对象?我该如何进行?预先感谢您的帮助:)

7 个答案:

答案 0 :(得分:5)

如果用Companion注释方法/属性,则可以摆脱@JvmStatic关键字

答案 1 :(得分:4)

In order to access Companion object attributes and methods, it is NOT required to have an instance of the Parent object. Companion object are already instantiated, therefore you can access the instance directly.

Instead of using <import> (which is the natural translation from Java), we need to use <variable>, because we actually want to use the (already instantiated) Companion object into our XML Layout.

Import your Companion object as follow

Given Kotlin class:

package com.example.project

class MyViewModel {
    companion object {
        // it is only working with val and var
        // const val wouldn't work
        val MAX_LENGTH = 10
    }
}

Layout:

    <data>
        <!-- Declare your "variable" that hold the Companion object itself -->
        <variable name="myViewModelStatic" type="com.example.project.MyViewModel.Companion" />
    </data>

    <!-- then use the myViewModelStatic to access "static" properties of MyViewModel -->
    <EditText
    ...
    android:maxLength="@{ myViewModelStatic.MAX_LENGTH }"
    />
</layout>

Fragment:

class MyFragment {
    ...
    onViewCreated(...) {
         // now bind the companion object to the variable declared in the XML
         binding.myViewModelStatic = TransferUseCase.Companion
    }
    ...
}

答案 2 :(得分:1)

还有另一种方法: 在课堂上

const val SomeProperty = "hey"
class MyClass {}

以XML格式

  <data>
    <import type="package.MyClassKt"/>
  </data>

  <TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="@{MyClassKt.SomeProperty}"/>

答案 3 :(得分:0)

在XML中,只需在字段名称前添加伴侣,例如:

在ViewModel中

package com.example.project

class MyViewModel {
    companion object {
        var leText = "text"
    }

    var leColor = ...
}

在XML

<data>
    <import type="android.view.View" />
    <variable 
        name="context"
        type="com.example.project.MyViewModel" />
</data>

<TextView
    ...
    android:text="@{context.Companion.leText}"
    android:color="@{context.leColor}"/>

答案 4 :(得分:0)

TL; DR:

替换

android:text="@{MyClass.Companion.SomeProperty}"

使用

android:text="@{MyClass.Companion.getSomeProperty()}"

说明:

您的问题是您试图完全按其名称引用Kotlin对象,但这不是Kotlin编译器在Java中生成属性的方式。相反,它将使用成为“ get”函数的Java约定对其进行转换。

您可以通过反编译Kotlin字节码来找出此名称的外观。

  1. 打开要查看其字节码的Kotlin类。
  2. 打开Tools> Kotlin> Show Kotlin Bytecode
  3. 在打开的侧面板中,单击左上角的Decompile按钮。

这将向您显示Kotlin类的Java等价物,包括伴随属性的全名。

奖金

也就是说,您可能希望将字段引用为属性,在这种情况下,您可以将const键盘附加到属性声明中。

const val SomeProperty = "hey"

这样,编译器将在public static之外将字段生成为Companion字段,并且您可以将xml更新为简单的:

android:text="@{MyClass.SomeProperty}"

与Java差不多,这是什么。

希望有帮助!

答案 5 :(得分:0)

要访问您的媒体资源,请执行以下操作:

使用以下注释您的随播对象属性 @JvmStatic

class MyClass {
  companion object {
   @JvmStatic
    val SomeProperty = "hey"
  }
}

然后继续,从绑定的TextView中删除“伴侣”:

更改
 <TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="@{MyClass.Companion.SomeProperty}"/>

 <TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="@{MyClass.SomeProperty}"/>

答案 6 :(得分:0)

我经历了所有这些答案,不得不提出自己的解决方案。

使用const val修饰符标记常量( const 为键),然后导入“父”类(在您的情况下为MyClass),并且不需要单词伴侣

class MyClass {
  companion object {
    const val SomeProperty = "hey"
  }
}

XML

  <data>
    <import type="package.MyClass"/>
  </data>

  <TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="@{MyClass.SomeProperty}"/>

</layout>