数据绑定:InputMethodManager:startInputInner - mService.startInputOrWindowGainedFocus
Databinding : InputMethodManager: startInputInner - mService.startInputOrWindowGainedFocus
出于安全需要,我使用 setText
的 char 数组 版本以避免使用 String
版本。
public final void setText (char[] text,
int start,
int len)
绑定适配器:
public class DataBindingAdapter {
@BindingAdapter("android:text")
public static void setCharArray(ClearableEditText view, char[] value) {
if(value == null) return;
Log.v("BindingAdapter", String.valueOf(value));
view.setText(value, 0, value.length);
}
@InverseBindingAdapter(attribute = "android:text")
public static char[] getArrayFromText(ClearableEditText view) {
int length = view.getText().length();
char[] password = new char[length];
view.getText().getChars(0, length, password, 0);
Log.v("BindingAdapter", String.valueOf(password));
return password;
}
}
模拟器行为:
但问题是当我在 EditText
中输入 ABCD 时,我得到了 DCBA 显示并且焦点始终位于EditText
.
的开头
真实设备行为:
只显示第一个字符。
日志:
2020-02-04 17:37:43.760 4110-4110/com.bla V/InputMethodManager:
Starting input: tba=com.bla
ic=com.android.internal.widget.EditableInputConnection@3e6e221
mNaviBarColor -16750956 mIsGetNaviBarColorSuccess true , NavVisible :
true , NavTrans : false 2020-02-04 17:37:43.760 4110-4110/com.bla
D/InputMethodManager: startInputInner - Id : 0 2020-02-04 17:37:43.767
4110-4110/com.bla I/InputMethodManager: startInputInner -
mService.startInputOrWindowGainedFocus
IMO CharArray
数据绑定很糟糕,因为当我将 CharArray
更改为 String
时没有问题,这意味着 equals
方法被生成的代码破坏了。
@BindingAdapter("android:text")
public static void setCharArray(EditText view, char[] value) {
if(value == null) return;
int length = view.length();
char[] password = new char[length];
view.getText().getChars(0, length, password, 0);
if (Arrays.equals(value, password)) {
Log.v("BindingAdapter out" + view.getId(), String.valueOf(value));
view.setText(value, 0, value.length);
}
}
编辑 1:更好的解决方案
使用 custom class that implement CharSequence
and hence the adapter version of setText 是基于 CharSequence
我这边不需要 BindingAdapter
。
class SecureString(value: CharArray?) : CharSequence {
@Transient
private val value: CharArray
init {
requireNotNull(value) { "Value must not be null" }
this.value = value
}
override val length: Int
get() = value.size
override fun get(index: Int): Char = value[index]
override fun subSequence(start: Int, end: Int): CharSequence {
throw UnsupportedOperationException()
}
fun clear() {
Arrays.fill(value, '\u0000')
}
fun toCharArray(): CharArray {
return value
}
}
将InverseBindingAdapter
调整为return SecureString
:
@InverseBindingAdapter(attribute = "android:text")
public static SecureString getSecureString(EditText view) {
int length = view.length();
SecureString password = new SecureString(new char[length]);
view.getText().getChars(0, length, password.toCharArray(), 0);
return password;
}
出于安全需要,我使用 setText
的 char 数组 版本以避免使用 String
版本。
public final void setText (char[] text,
int start,
int len)
绑定适配器:
public class DataBindingAdapter {
@BindingAdapter("android:text")
public static void setCharArray(ClearableEditText view, char[] value) {
if(value == null) return;
Log.v("BindingAdapter", String.valueOf(value));
view.setText(value, 0, value.length);
}
@InverseBindingAdapter(attribute = "android:text")
public static char[] getArrayFromText(ClearableEditText view) {
int length = view.getText().length();
char[] password = new char[length];
view.getText().getChars(0, length, password, 0);
Log.v("BindingAdapter", String.valueOf(password));
return password;
}
}
模拟器行为:
但问题是当我在 EditText
中输入 ABCD 时,我得到了 DCBA 显示并且焦点始终位于EditText
.
真实设备行为:
只显示第一个字符。
日志:
2020-02-04 17:37:43.760 4110-4110/com.bla V/InputMethodManager: Starting input: tba=com.bla ic=com.android.internal.widget.EditableInputConnection@3e6e221 mNaviBarColor -16750956 mIsGetNaviBarColorSuccess true , NavVisible : true , NavTrans : false 2020-02-04 17:37:43.760 4110-4110/com.bla D/InputMethodManager: startInputInner - Id : 0 2020-02-04 17:37:43.767 4110-4110/com.bla I/InputMethodManager: startInputInner - mService.startInputOrWindowGainedFocus
IMO CharArray
数据绑定很糟糕,因为当我将 CharArray
更改为 String
时没有问题,这意味着 equals
方法被生成的代码破坏了。
@BindingAdapter("android:text")
public static void setCharArray(EditText view, char[] value) {
if(value == null) return;
int length = view.length();
char[] password = new char[length];
view.getText().getChars(0, length, password, 0);
if (Arrays.equals(value, password)) {
Log.v("BindingAdapter out" + view.getId(), String.valueOf(value));
view.setText(value, 0, value.length);
}
}
编辑 1:更好的解决方案
使用 custom class that implement CharSequence
and hence the adapter version of setText 是基于 CharSequence
我这边不需要 BindingAdapter
。
class SecureString(value: CharArray?) : CharSequence {
@Transient
private val value: CharArray
init {
requireNotNull(value) { "Value must not be null" }
this.value = value
}
override val length: Int
get() = value.size
override fun get(index: Int): Char = value[index]
override fun subSequence(start: Int, end: Int): CharSequence {
throw UnsupportedOperationException()
}
fun clear() {
Arrays.fill(value, '\u0000')
}
fun toCharArray(): CharArray {
return value
}
}
将InverseBindingAdapter
调整为return SecureString
:
@InverseBindingAdapter(attribute = "android:text")
public static SecureString getSecureString(EditText view) {
int length = view.length();
SecureString password = new SecureString(new char[length]);
view.getText().getChars(0, length, password.toCharArray(), 0);
return password;
}