如何正确地将数字双向绑定到Android editText

Aut*_*umn 6 android android-databinding

我必须在这里遗漏一些东西.我在Android的双向绑定中看到的每个例子都基于String用户可输入的任何内容的支持数据,例如EditText.

处理任何不是字符串的东西似乎有点......不优雅.例如,如果我的域模型中有一个需要可编辑的双,那么我提出的最好的绑定需要一个ViewModel令人惊讶的很多代码来连接模型和模型EditText.

我错过了什么关键吗?我真的需要30行代码才能EditText与双重接口吗?为了便于讨论,让我们考虑一个货币字段,以双向方式表示为双向EditText:

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:text="@={fragModel.startBucks}"
android:id="@+id/editText2"/>
Run Code Online (Sandbox Code Playgroud)

这里是我必须构造的ViewModel,以便为EditText提供一个绑定的字符串.

@Bindable private String startBucksString;
private double localBucks;
public String getStartBucksString() {
    double domainBucks = cd.getStartBucks();
    // Ignore incoming change of less than rounding error
    if( Math.abs(localBucks - domainBucks) < .001  ) return startBucksString;
    startBucksString = "";
    if( domainBucks != 0)
        startBucksString = String.format("$%.2f", domainBucks);
    return startBucksString;
}

public void setStartBucksString(String inBuckstr) {
    double calcBucks=0;
    inBuckstr = inBuckstr.replaceAll( "[^\\d.]", "" );
    try {
         calcBucks = Double.parseDouble(inBuckstr);
    } catch( NumberFormatException e) {
        return;
    }
    // Neglect outgoing change of less than rounding error
    if( Math.abs(localBucks - calcBucks) < .001  ) return;

    startBucksString = String.format("$%.2f", calcBucks);
    localBucks = calcBucks;
    cd.setStartBucks(calcBucks);
    notifyPropertyChanged(BR.startBucksString);
}
Run Code Online (Sandbox Code Playgroud)

在这里,我编写了一个简单,可编译的与ViewModel进行双向绑定的示例.它说明了我在连续更新域模型中的浮点数时遇到的困难 - 最后,我决定如果不为每个域字段编写自定义TextWatcher,就无法做到这一点.

And*_*san 1

我的方法是使用句柄延迟调用notifyPropertyChanged 方法。这样,当用户键入时,代码不会运行,然后在用户停止键入最后一个字符后 2.5 秒,将调用 notificationPropertyChanged。

视觉效果炫酷,用户可以随意书写数字。

看这两个例子:

使用可以对每个字段使用这个紧凑(?)代码:

//
// g1FuelCostYear field
//
private double g1FuelCostYear;

@Bindable
public String getG1FuelCostYear() {
  return Double.valueOf(g1FuelCostYear).toString();
}

private Handler hG1FuelCostYearDelay = null;

public void setG1FuelCostYear(String g1FuelCostYear) {

  // Delayed notification hadler creation
  if (hG1FuelCostYearDelay == null) {
    hG1FuelCostYearDelay = new Handler() {
      @Override
      public void handleMessage(Message msg) {
        notifyPropertyChanged(it.techgest.airetcc2.BR.g1FuelCostYear);
      }
    };
  } else {
    // For each call remove pending notifications
    hG1FuelCostYearDelay.removeCallbacksAndMessages(null);
  }

  // Data conversion logic
  try {
    this.g1FuelCostYear = Double.parseDouble(g1FuelCostYear);
  }
  catch (Exception ex) {
    this.g1FuelCostYear = 0.0;
    log(ex);
  }

  // New delayed field notification (other old notifications are removed before)
  hG1FuelCostYearDelay.sendEmptyMessageDelayed(0,2500);
}
Run Code Online (Sandbox Code Playgroud)

当您使用货币转换器或百分比转换器时,此代码非常有用。用户可以编写一个普通的双精度数,代码转换为货币字符串。如果使用货币字符串调用设置器,代码也可以将其转换为双精度。

//
// g1FuelCostYear field
//
private double g1FuelCostYear;

@Bindable
public String getG1FuelCostYear() {
  NumberFormat nf = NumberFormat.getCurrencyInstance();
  return nf.format(this.g1FuelCostYear);
  //return Double.valueOf(g1FuelCostYear).toString();
}

private Handler hG1FuelCostYearDelay = null;

public void setG1FuelCostYear(String g1FuelCostYear) {
  if (hG1FuelCostYearDelay == null)
  {
    hG1FuelCostYearDelay = new Handler() {
      @Override
      public void handleMessage(Message msg) {
          notifyPropertyChanged(it.techgest.airetcc2.BR.g1FuelCostYear);
      }
    };
  } else {
      hG1FuelCostYearDelay.removeCallbacksAndMessages(null);
  }
  boolean success = false;
  try {
    NumberFormat nf = NumberFormat.getCurrencyInstance();
    this.g1FuelCostYear = nf.parse(g1FuelCostYear).doubleValue();
    success = true;
  }
  catch (Exception ex) {
    this.g1FuelCostYear = 0.0;
    log(ex);
  }
  if (!success) {
    try {
        this.g1FuelCostYear = Double.parseDouble(g1FuelCostYear);
        success = true;
    } catch (Exception ex) {
        this.g1FuelCostYear = 0.0;
        log(ex);
    }
  }
  updateG1FuelConsumption();
  hG1FuelCostYearDelay.sendEmptyMessageDelayed(0,2500);
}
Run Code Online (Sandbox Code Playgroud)