0

나는 this 블로그 게시물을 따라 사용자 지정 구성 요소 (EditText가 포함 된 제약보기)에서 작동하도록 양방향 데이터 바인딩을 시도하려고합니다.맞춤 구성 요소에 대한 Android 양방향 데이터 바인딩?

두 가지 표준 EditText 구성 요소를 내 모델과 동기화 (두 가지 방법 모두) 할 수 있지만 사용자 정의 구성 요소의 변경 사항을 내 모델로 전달하는 데 문제가 있습니다 (단방향 데이터 바인딩 공장).

내 모델 :

public class Model extends BaseObservable { 
    private String value; 

    @Bindable 
    public String getValue() { 
     return value; 
    } 

    public void setValue(String value) { 
     this.value = value; 
     notifyPropertyChanged(company.com.databinding.BR.value); 
    } 

    public Model() { 
     value = "Value"; 
    } 
} 

활동 :

@InverseBindingMethods({ 
     @InverseBindingMethod(
       type = CustomComponent.class, 
       attribute = "value", 
       method = "getValue") 
}) 
public class MainActivity extends AppCompatActivity { 
    @BindingAdapter("value") 
    public static void setColor(CustomComponent view, String value) { 
     if (!value.equals(view.getValue())) { 
      view.setValue(value); 
     } 
    } 

    @BindingAdapter(
      value = {"onValueChange", "valueAttrChanged"}, 
      requireAll = false 
    ) 
    public static void setListeners(CustomComponent view, 
            final ValueChangeListener onValueChangeListener, 
            final InverseBindingListener inverseBindingListener) { 
     ValueChangeListener newListener; 
     if (inverseBindingListener == null) { 
      newListener = onValueChangeListener; 
     } else { 
      newListener = new ValueChangeListener() { 
       @Override 
       public void onValueChange(CustomComponent view, 
              String value) { 
        if (onValueChangeListener != null) { 
         onValueChangeListener.onValueChange(view, 
           value); 
        } 
        inverseBindingListener.onChange(); 
       } 
      }; 
     } 

     ValueChangeListener oldListener = 
       ListenerUtil.trackListener(view, newListener, 
         R.id.textWatcher); 

     if (oldListener != null) { 
      view.removeListener(oldListener); 
     } 
     if (newListener != null) { 
      view.addListener(newListener); 
     } 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     //setContentView(R.layout.activity_main); 
     ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); 
     binding.setModel(new Model()); 
    } 
} 

사용자 정의 구성 요소 :

public class CustomComponent extends ConstraintLayout { 
    private String value; 
    private EditText txt; 
    private TextWatcher textWatcher; 
    ValueChangeListener listener; 

    public String getValue() { 
     return value; 
    } 

    public void setValue(String value) { 
     this.value = value; 
     if (txt != null) { 
      txt.setText(value); 
     } 
    } 

    public CustomComponent(Context context) { 
     super(context); 
     init(context); 
    } 

    public CustomComponent(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(context, attrs); 
    } 

    public CustomComponent(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     init(context, attrs); 
    } 

    private void init(Context context) { 

    } 

    private void init(Context context, AttributeSet attrs) { 
     View.inflate(context, R.layout.custom_component, this); 
     txt = findViewById(R.id.txt_box); 
     final CustomComponent self = this; 
     textWatcher = new TextWatcher() { 
      @Override 
      public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { 

      } 

      @Override 
      public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { 

      } 

      @Override 
      public void afterTextChanged(Editable editable) { 
       if (listener != null) { 
        listener.onValueChange(self, editable.toString()); 
       } 
      } 
     }; 
     txt.addTextChangedListener(textWatcher); 
    } 

    public void addListener(ValueChangeListener listener) { 
     this.listener = listener; 
    } 

    public void removeListener(ValueChangeListener listener) { 
     this.listener = null; 
    } 
} 

public interface ValueChangeListener { 
    public void onValueChange(CustomComponent view, String value); 
} 

그 게시물에 "이벤트를 후킹"섹션을 통해 완전히 사라 졌 생각 내 머리; 난 정말 구성 요소에 대한 간단한 setter 및 getter가 필요하므로 BindingAdapter에서 수행 된 작업을 이해할 수 없습니다.

ValueChangeListener oldListener = 
      ListenerUtil.trackListener(view, newListener, 
        R.id.textWatcher); 

데모에서 : https://github.com/indgov/data_binding

답변

1

ListenerUtil 혼란이었다 죄송합니다 그들 모두의 나는 내가 전혀하지 않는이 줄을 생각합니다. 구성 요소가 여러 수신기를 지원하는 경우에만 유용합니다. 이 경우 새 리스너를 설정할 수 없으므로 이전 리스너를 제거하고 새 리스너를 추가해야합니다. ListenerUtil을 사용하면 이전 수신기를 추적하여 제거 할 수 있습니다.

@BindingAdapter(
     value = {"onValueChange", "valueAttrChanged"}, 
     requireAll = false 
) 
public static void setListeners(CustomComponent view, 
           final ValueChangeListener onValueChangeListener, 
           final InverseBindingListener inverseBindingListener) { 
    ValueChangeListener newListener; 
    if (inverseBindingListener == null) { 
     newListener = onValueChangeListener; 
    } else { 
     newListener = new ValueChangeListener() { 
      @Override 
      public void onValueChange(CustomComponent view, 
             String value) { 
       if (onValueChangeListener != null) { 
        onValueChangeListener.onValueChange(view, 
          value); 
       } 
       inverseBindingListener.onChange(); 
      } 
     }; 
    } 

    view.setListener(newListener); 
} 

을 다음 setListener()addListener()를 교체하고 항상 null에 리스너를 설정할 수 있기 때문에 당신은 removeListener() 필요하지 않습니다 : 귀하의 경우에는, 그것은 간단하게 할 수 있습니다.

당신이보고있는 문제는 구성 요소에 : 당신은 마지막 세터로 설정하고 글고 치기에없는 값이 있던 값을 반환하고

public String getValue() { 
    return value; 
} 

. 이를 해결하려면 :

public String getValue() { 
    return txt.getText().toString(); 
} 
관련 문제