safeUnbox() 不能反转

safeUnbox() cannot be inverted

我正在尝试消除我的 Android 应用程序的所有警告,其中之一是:

viewModel.value is a boxed field but needs to be un-boxed to execute android:checked. This may cause NPE so Data Binding will safely unbox it. You can change the expression and explicitly wrap viewModel.value with safeUnbox() to prevent the warning

其中值是来自超级 class 的通用 ObservableField:

public abstract class BaseDataTypeViewModel<T> extends BaseObservable  {
    public final ObservableField<T> value = new ObservableField<>();
    ...
}

并在某处扩展为 Boolean:

public class CheckBooleanDataTypeViewModel extends BaseDataTypeViewModel<Boolean> {
    ...
}

我在 data binding - safeUnbox warning 上看到出现警告是因为这是 Boolean 而不是 boolean,所以我尝试添加:android:checked="@={safeUnbox(viewModel.value)}" 而不是 android:checked="@={viewModel.value}" 但后来我收到一条错误消息,提示我无法反转 safeUnbox() 方法。

****/ data binding error ****msg:The expression android.databinding.DynamicUtil.safeUnbox(viewModelValue) cannot be inverted: There is no inverse for method safeUnbox, you must add an @InverseMethod annotation to the method to indicate which method should be used when using it in two-way binding expressions

我正确理解了这 2 个独立的问题,但我是否必须忍受警告以避免错误,或者它们是否是同时避免警告和错误的解决方案?它所说的 @InverseMethod 呢?我没有设法添加此注释,因为该方法来自 android 包。

我没有以这种特殊方式使用 Android 架构组件或数据绑定库,但我认为我仍然可以提供帮助。

在你的 XML 中,你得到了这个:

android:checked="@={viewModel.value}"

系统给你一个警告是因为它想让你知道在 viewModel.valuenull 的情况下,它会做一些特别的事情(表现得好像它是 false 相反,大概)。它通过 safeUnbox() 方法实现。

为了解决警告,建议显式调用 safeUnbox()。你不能那样做,因为 safeUnbox() 中没有 "inverse" 从 booleanBoolean.[=27= back ]

但听起来你不必使用 safeUnbox();您可以创建自己的将 Boolean 转换为 boolean 的方法,然后您可以使用建议的注释来声明哪个方法将从 boolean 转换回 Boolean

public class MyConversions {

    @InverseMethod("myBox")
    public static boolean myUnbox(Boolean b) {
        return (b != null) && b.booleanValue();
    }

    public static Boolean myBox(boolean b) {
        return b ? Boolean.TRUE : Boolean.FALSE;
    }
}

现在您可以将 XML 更改为:

android:checked="@={com.example.Whosebug.MyConversions.myUnbox(viewModel.value)}"

希望对您有所帮助。如果事实证明我偏离了基地,请告诉我;我很想了解有关此主题的更多信息。

我在这个答案中的大部分内容都是从 https://medium.com/google-developers/android-data-binding-inverse-functions-95aab4b11873

中学到的

遇到这个问题并找到了更简单的解决方案。您可以通过为这样的盒装类型创建自定义 BindingAdapter 来避免此警告:

@BindingAdapter("android:checked")
public static void setChecked(CompoundButton checkableView, Boolean isChecked) {
    checkableView.setChecked(isChecked != null ? isChecked : false);
}

此解决方案可以复制到任何 属性,如 visibilityenabled 等,以及任何盒装原语,如 IntegerFloat 等。

您还可以提供要使用的值,以防您的 LiveData 值为 null,如下所示:

@BindingAdapter(value={"android:checked", "nullValue"}, requireAll=false)
public static void setChecked(CompoundButton checkableView, Boolean isChecked, boolean nullValue) {
    checkableView.setChecked(isChecked != null ? isChecked : nullValue);
}

并这样称呼它:

<CheckBox
    ...
    android:checked='@{viewModel.value}'
    app:nullValue="@{false}"
    />

在 xml 中这样做。最后一行代码是最重要的。

<layout>

  <data>
    <import type="android.view.View"/>
    <variable name="entryViewModel"
        type="com.craiovadata.groupmap.viewmodel.EntryViewModel" />
  </data>

  <Button 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="@{safeUnbox(entryViewModel.showBtnMyGroups) ? View.VISIBLE : View.GONE, default = gone}" />

我找到一个代码,这个safeUnbox实现。

/** @hide */
protected static int safeUnbox(java.lang.Integer boxed) {
    return boxed == null ? 0 : (int)boxed;
}

/** @hide */
protected static long safeUnbox(java.lang.Long boxed) {
    return boxed == null ? 0L : (long)boxed;
}

/** @hide */
protected static short safeUnbox(java.lang.Short boxed) {
    return boxed == null ? 0 : (short)boxed;
}

/** @hide */
protected static byte safeUnbox(java.lang.Byte boxed) {
    return boxed == null ? 0 : (byte)boxed;
}

/** @hide */
protected static char safeUnbox(java.lang.Character boxed) {
    return boxed == null ? '\u0000' : (char)boxed;
}

/** @hide */
protected static double safeUnbox(java.lang.Double boxed) {
    return boxed == null ? 0.0 : (double)boxed;
}

/** @hide */
protected static float safeUnbox(java.lang.Float boxed) {
    return boxed == null ? 0f : (float)boxed;
}

/** @hide */
protected static boolean safeUnbox(java.lang.Boolean boxed) {
    return boxed == null ? false : (boolean)boxed;
}

所以,如果你的值不是基本类型,你不能直接使用safeUnbox,你应该自己定义一个静态函数来安全拆箱。