标签:android android-databinding
TL; DR:如果与数据绑定一起使用的布局具有EditText,并且有一个用于android:text的绑定表达式,则绑定表达式将覆盖保存的实例状态值…即使我们没有明确触发绑定评估.用户在配置更改消失之前键入的内容.我们如何解决这个问题,以便在配置更改时使用保存的实例状态值?
我们有一个愚蠢的模型:
public class Model {
public String getTitle() {
return("Title");
}
}
我们有一个引用该模型的布局:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="model"
type="com.commonsware.databindingstate.Model" />
</data>
<android.support.constraint.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.commonsware.databindingstate.MainActivity">
<EditText android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</layout>
请注意,此布局没有绑定表达式;我们稍后会谈到这一点.
布局用于动态片段:
public class FormFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return(MainBinding.inflate(inflater, container, false).getRoot());
}
}
请注意,我们不会在任何地方调用setModel()来将模型推送到绑定中. MainBinding(对于上面显示的main.xml布局)仅用于夸大布局.
此代码(具有合适的FragmentActivity来设置FormFragment)正确使用已保存的实例状态.如果用户在EditText中键入内容,然后旋转屏幕,则新重新创建的EditText会显示输入的文本.
现在,让我们更改布局为android:text添加绑定表达式:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="model"
type="com.commonsware.databindingstate.Model" />
</data>
<android.support.constraint.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.commonsware.databindingstate.MainActivity">
<EditText android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:inputType="text"
android:text="@{model.title}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</layout>
现在,如果用户在EditText中键入内容并旋转屏幕,则新重新创建的EditText为空.绑定表达式将覆盖从保存的实例状态恢复的框架.
尽管事实上我没有在绑定上调用setModel(),但这仍然存在.我当然可以看到我在绑定上调用setModel()的位置,它将使用模型中的数据替换EditText内容.但我不这样做.
我可以在官方设备(Google Pixel,Android 8.0)和生态系统设备(Samsung Galaxy S8,Android 7.1)上重现此行为.
这可以通过自己保存状态并在某些时候恢复它来“手动”解决.例如,多个注释建议双向绑定,但这与其他设计目标(例如,不可变模型对象)相反.这似乎是数据绑定的一个相当基本的限制,所以我希望有一些我错过的东西,我可以配置为自动使用保存的实例状态.
解决方法:
我认为ianhanniballake提到了一个相关的答案,但也许还有更多.以下是我对该参考如何应用于这些情况的解释.
使用您提供的XML,以下代码将交替从已保存的实例状态还原并从模型还原.当恢复保存的实例状态时,可能是没有实例化的模型要从中恢复.那是mCount是偶数的时候.如果存在模型,则基本上忽略保存的实例状态并且绑定接管.这里有一个比我们想要的更多的逻辑,但它不是明确地保存和恢复.
为了论证,mCount只是一个技巧.将使用标志或是否存在模型的其他指示.
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private int mCount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mCount = (savedInstanceState == null) ? 0 : savedInstanceState.getInt("mCount", 0);
if (mCount % 2 == 1) {
// 1st, 3rd, 5th, etc. rotations. Explicitly execute the bindings and let the framework
// restore from the saved instance state.
binding.executePendingBindings();
} else {
// First creation and 2nd, 4th, etc. rotations. Set up our model and let the
// framework restore from the saved instance state then overwrite with the bindings.
// (Or maybe it just ignores the saved instance state and restores the bindnings.)
Model model = new Model();
binding.setModel(model);
}
mCount++;
}
@Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putInt("mCount", mCount);
}
}
标签:android,android-databinding 来源: https://codeday.me/bug/20190701/1348736.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。