简体   繁体   English

如何格式化ObservableField(double)DataBinding?

[英]How to format an ObservableField (double) DataBinding?

So, I have the very simple problem, that I cannot seem to format a double coming from an ObservableField in a data binding. 因此,我有一个非常简单的问题,即我似乎无法在数据绑定中格式化来自ObservableField的双精度格式。 I have the following layout: 我有以下布局:

android:text='@{String.format("%.2f€", transaction.value)}'

and here the definition of transaction.value: 这里是transaction.value的定义:

public final ObservableField<Double> value = new ObservableField<>();

I always get this error: 我总是收到此错误:

java.util.IllegalFormatConversionException: f != android.databinding.ObservableField java.util.IllegalFormatConversionException:f!= android.databinding.ObservableField

I get the same issue if I use an ObservableDouble. 如果使用ObservableDouble,则会遇到相同的问题。 The only way to avoid this seems to be if I call transaction.value.get() in the binding, but I was under the impression that get/set can be omitted here, as I am successfully doing eg with an ObservableField<Date> . 避免这种情况的唯一方法似乎是如果我在绑定中调用transaction.value.get() ,但我的印象是这里可以省略get / set,因为我已经成功地使用了ObservableField<Date>

I am targeting Sdk 26 with with buildTools 26.0.2. 我的目标是通过buildTools 26.0.2实现Sdk 26。

Update 1 更新1

I tried the same thing now with my previous setup, and it worked, just as I remembered. 我记得以前,现在我在以前的设置中尝试了相同的操作,并且可以正常工作。 So I pinpointed it to the Gradle version change from 2.3.1 to 3.0.1 (even when I put in target/compile Sdk 26 and buildToolsVersion 26.0.2 with Gradle 2.3.1 it works). 因此,我将其精确定位到了从2.3.1到3.0.1的Gradle版本更改(即使当我将目标/编译Sdk 26和buildToolsVersion 26.0.2与Gradle 2.3.1一起使用时也可以正常工作)。

As @dominicoder pointed out to look into the generated data bindings, here is the difference, explaining the problem: 正如@dominicoder指出要研究生成的数据绑定一样,这是区别,解释了问题:

Gradle 2.3.1: 摇篮2.3.1:

android.databinding.ObservableField<java.lang.Double>transactionValue=null;
java.lang.Double transactionValueGet=null;
....
if(transaction!=null){
    // read transaction.value
    transactionValue=transaction.value;
}
updateRegistration(3,transactionValue);
if(transactionValue!=null){
    // read transaction.value.get()
    transactionValueGet=transactionValue.get();
}
// read String.format("%.2f€", transaction.value.get())
stringFormatJavaLangString2fTransactionValue=java.lang.String.format("%.2f€",transactionValueGet);

Gradle 3.0.1: 摇篮3.0.1:

android.databinding.ObservableField<java.lang.Double> transactionValue = null;
// NO transactionValueGet field !!!
....
if(transaction!=null){
    // read transaction.value
    transactionValue=transaction.value;
}
updateRegistration(3,transactionValue);
// read String.format("%.2f€", transaction.value)
stringFormatJavaLangString2fTransactionValue=java.lang.String.format("%.2f€",transactionValue);

So - it looks like this is a bug introduced in that version update (to be safe, I created a completely new project with a similar setting, a TextView having its text bound to an ObservableField<Double> using String.format() ). 所以-看来这是该版本更新中引入的错误(为了安全起见,我创建了一个具有类似设置的全新项目,一个TextView使用String.format()将其文本绑定到ObservableField<Double> )。 Or maybe it is intended behavior, but I really wouldn't understand the purpose of that kind ob breaking change. 也许这是预期的行为,但我真的不理解这种破坏变革的目的。

Update 2 更新2

Currently the problem is filed in the Android issue tracker 目前,问题已在Android问题跟踪器中提出

The Problem 问题

Check the databinding generated java file for your layout. 检查您的布局的数据绑定生成的java文件。 You will find something like this: 您会发现类似以下内容:

android.databinding.ObservableField<java.lang.Double> transactionValue = null;
// read String.format("%.2f€", accountViewModel.test)
stringFormatJavaLangString2fAccountViewModelTest = java.lang.String.format("%.2f€", transactionValue);

You can see that it's using the observable field literally and I think it's because the signature of String.format is (String string, Object args...) . 您可以看到它实际上是在使用observable字段,我认为这是因为String.format的签名是(String string, Object args...) Because the observable field is an Object it can be used as is, so the code generator does not try to "get" the double value instead. 由于可观察字段是一个Object因此可以按原样使用它,因此代码生成器不会尝试“获取”双精度值。

The Date formatting example works because the format method has a signature of (Date date) . Date格式示例有效,因为format方法的签名为(Date date) Thus, the code generator realizes that the signature doesn't match, but the observable type does, so it "get"s it for you and you'll see something like this: 因此,代码生成器意识到签名不匹配,但是可观察类型匹配,因此它为您“获取”签名,您将看到类似以下内容:

java.util.Date transactionDateGet = null;
// read transaction.date.get()
transactionDateGet = transactionDate.get();

androidTextFormatDateFormatGetDateFormatContextFormatTransactionDate =
    android.text.format.DateFormat.getDateFormat(
        getRoot().getContext()).format(transactionDateGet);

The Solution 解决方案

As you already indicated, the easiest thing to do is just manually call .get() in your binding. 正如您已经指出的,最简单的方法是在绑定中手动调用.get() However, I'd recommend avoiding doing logic in your XML, as @elmorabea indicated. 但是,我建议避免在XML中执行逻辑,如@elmorabea所示。 Instead, I'd suggest using a view model that encapsulates the display logic: 相反,我建议使用封装显示逻辑的视图模型:

public class TransactionViewModel {
    private final Transaction mTransaction;

    public TransactionViewModel(@NonNull Transaction transaction) {
        mTransaction = transaction;
    }

    @Bindable
    public String getTransactionValueText() {
        return String.format("%.2f€", transaction.getValue());
    }
}

Then you have something like this: 然后,您将得到如下内容:

android:text='@{viewModel.transactionValueText}'

This is more work as you have to have an extra class for each layout file; 这是更多的工作,因为每个布局文件都必须有一个额外的类。 you'd have to move your observable fields from your models to the viewmodels; 您必须将可观察字段从模型移至视图模型; and you'd have to make your view model obvserve the model to propagate the changes up the to view, but the separation of concerns makes it far easier to update, extend, reuse, and maintain in the long run. 并且您必须使您的视图模型遵守该模型以将更改传播到视图,但是从长远来看,关注点的分离使更新,扩展,重用和维护变得更加容易。

Hope that helps! 希望有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何处理警告:未经检查调用 &#39;ObservableField(T)&#39; 作为原始类型 &#39;android.databinding.ObservableField&#39; 的成员 - How to handle warning:Unchecked call to 'ObservableField(T)' as a member of raw type 'android.databinding.ObservableField' 数据绑定 - ObservableField<String> 不更新视图 - Databinding - ObservableField<String> not updating view 数据绑定:自定义对象的ObservableField无法正常工作 - Databinding: ObservableField of custom object it is not working properly ObservableField 的使用<string> Android 数据绑定中的字符串</string> - Usage of ObservableField<String> over String in Android Databinding 如何在Android中获取ObservableField的值 - How to get value of the ObservableField in android 使用ObservableField &lt;&gt;,set()的双向数据绑定不起作用? - 2-way databinding with ObservableField<>, set() doesn't work? 如何改变 observableField 中的传入字符串 - How to mutate an incoming string in an observableField 如何在 Kotlin 中检测带有数据绑定的双击? - How to detect double-tap with databinding in Kotlin? 双向数据绑定(在xml中),ObservableField,BaseObservable,我应该用哪个双向数据绑定? - Two-way databinding(in xml), ObservableField, BaseObservable , which one I should use for the two-way databinding? 如何在内部控件中传递ObservableField - How to pass ObservableField inside internal control
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM