Combination controls are used in the project. This control is particularly used, but I also want to use the two-way binding function of DataBinding. Many blogs have written implementation steps. These logics are involved. This note is a summary of my use. .
I used to write in combination control the two-way binding, are interested can look. project
Control introduction
There is a combination of control EditText
, user to EditText
input new content, MutableLiveData
you can receive the content input through to MutableLiveData
the setValue()
new data can be achieved automatically update EditText
the content.
- Combination control code
public class CustomeEditTextView extends FrameLayout {
private EditText mEtContent;
// SET 方法
@BindingAdapter("y_content")
public static void setStr(CustomeEditTextView cetv, String content) {
if (cetv != null) {
String mCurrentStr = cetv.mEtContent.getText().toString().trim();
if (!TextUtils.isEmpty(content)) {
if (!content.equalsIgnoreCase(mCurrentStr)) {
cetv.mEtContent.setText(content);
// 设置光标位置
cetv.mEtContent.setSelection(content.length());
}
}
}
}
// GET 方法
@InverseBindingAdapter(attribute = "y_content", event = "contentAttrChanged")
public static String getStr(CustomeEditTextView cetv) {
return cetv.mEtContent.getText().toString().trim();
}
// 监听,如果有变动就调用listener中的onChange方法
@BindingAdapter(value = "contentAttrChanged")
public static void setChangeListener(CustomeEditTextView cetv, InverseBindingListener listener) {
cetv.mEtContent.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
listener.onChange();
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
}
- Used in XML layout
<data>
<variable
name="mVM"
type="com.yey.MyVM" />
</data>
<com.yey.ycustomeview.CustomeEditTextView
android:id="@+id/cetv_1"
android:layout_width="match_parent"
android:layout_height="60dp"
app:y_content="@={mVM.mContentMLD1}"/>
- Use code
// MyVM.java
public class MyVM extends ViewModel {
public MutableLiveData<String> mContentMLD1;
public MyVM() {
mContentMLD1 = new MutableLiveData<>();
}
}
// MainActivity.java
public class MainActivity extends AppCompatActivity {
private MyVM myVM;
@Override
protected void onCreate(Bundle savedInstanceState) {
initVM();
}
private void initVM() {
myVM = new ViewModelProvider(this).get(MyVM.class);
mainBinding.setMVM(myVM);
myVM.mContentMLD1.setValue("1");
}
}
The above are the steps of use and implementation. Do the three methods of implementation seem clueless? Let's see below.
Internal logic analysis
myVM.mContentMLD1.setValue("1")
- When the program is called , the method will
myVM.mContentMLD1.setValue("1")
eventually be calledActivityMainBindingImpl.executeBindings()
, and the method defined in the combined control will be called in thissetStr(CustomeEditTextView cetv, String content)
method.
public class ActivityMainBindingImpl extends ActivityMainBinding {
@Override
protected void executeBindings() {
//1. read mVM.mContentMLD1 这里是获取MyVM中的MutableLiveData类型的mContentMLD1对象
mVMMContentMLD1 = mVM.mContentMLD1;
//2. 获取mContentMLD1中的值
mVMMContentMLD1GetValue = mVMMContentMLD1.getValue();
//3. 调用组合控件中的setStr()方法,最终将mVMMContentMLD1中的值取出后赋值给EditText对象.
com.yey.ycustomeview.CustomeEditTextView.setStr(this.cetv1, mVMMContentMLD1GetValue);
}
}
InverseBindingListener.onChange();
- The
EditText
input change is monitored in the combined control, and it will be called whenever the input changesInverseBindingListener.onChange();
. Let's seeonChange()
the specific implementation of the method below.
public class ActivityMainBindingImpl extends ActivityMainBinding {
private androidx.databinding.InverseBindingListener cetv1contentAttrChanged = new androidx.databinding.InverseBindingListener() {
@Override
public void onChange() {
// 通过组合控件中的getStr方法获取EditText当前的内容
java.lang.String callbackArg_0 = com.yey.ycustomeview.CustomeEditTextView.getStr(cetv1);
// 获取MyVM中的MutableLiveData类型的mContentMLD1对象
mVMMContentMLD1 = mVM.mContentMLD1;
// 将EditText当前的内容设置到mContentMLD1对象中
mVMMContentMLD1.setValue(((java.lang.String) (callbackArg_0)));
}
}
}
setChangeListener(CustomeEditTextView cetv, InverseBindingListener listener)
When is it called?
When itActivityMainBindingImpl.executeBindings()
is called, the setChangeListener(CustomeEditTextView cetv, InverseBindingListener listener) method is executed.
public class ActivityMainBindingImpl extends ActivityMainBinding {
@Override
protected void executeBindings() {
com.yey.ycustomeview.CustomeEditTextView.setChangeListener(this.cetv1, cetv1contentAttrChanged);
}
}
note
If you see here, you will find that there is an infinite call closed loop, EditText.setText()
-> TextWatcher.onTextChanged()
-> InverseBindingListener.onChange()
-> MutableLiveData.setValue()
-> EditText.setText()
, so setStr()
if the new data content EditText
is the same as the current content in the method, don't execute it again EditText.setText()
, so as to avoid it. Always call.