Add DataBinding two-way binding function when Android custom View

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 EditTextinput new content, MutableLiveDatayou can receive the content input through to MutableLiveDatathe setValue()new data can be achieved automatically update EditTextthe 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 called ActivityMainBindingImpl.executeBindings(), and the method defined in the combined control will be called in this setStr(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 EditTextinput change is monitored in the combined control, and it will be called whenever the input changes InverseBindingListener.onChange();. Let's see onChange()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 it ActivityMainBindingImpl.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 EditTextis the same as the current content in the method, don't execute it again EditText.setText(), so as to avoid it. Always call.

Guess you like

Origin blog.csdn.net/MoLiao2046/article/details/107977255