[英]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问题跟踪器中提出
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);
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.