问题描述
使用Android Jetpack组件和MVVM架构,我们可以通过两种方式从视图模型中的视图中获取实时数据更新,一种是将布局与实时数据变量绑定,另一种方式是在代码中观察变量。 为了说明我的问题,我举了一个例子。假设有一个视图模型接口getTimeString()返回当前时间。
a)布局数据绑定
-
布局中的视图看起来像这样
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" ... app:binder_data_date="@{sampleVM.timeString}"/>
-
绑定适配器看起来像这样
@BindingAdapter("binder_data_date") public static void binder_data_date(TextView text,String data) { text.setText(data); }
b)手动数据绑定(仅为其命名): 在“手动数据绑定”中,相对于活页夹而言,布局视图中没有任何内容,我使用observe()观察实时数据并更新了textview。
FragmentSplashScreenManualBindingBinding fragmentSplashScreenBinding;
SampleViewModel sampleViewModel1 = ViewModelProviders.of(this).get(SampleViewModel.class);
public void onSomeRandomFunc(...) {
....
sampleViewModel1.getTimeString().observe(getViewLifecycleOwner(),data -> {
fragmentSplashScreenBinding.sampleText.setText(data);
});
}
我知道第一种方法更容易使用,并且都可以使用。
- 但是是否使用第二种方法和方法来访问片段中的变量(fragmentSplashScreenBinding.sampleText.setText())以更新View是否正确?
- 如果使用第二种方法,性能会受到影响吗?
解决方法
您的手动数据绑定是不正确的,并且对性能没有明显影响,但是您将失去两个好处:
- 空指针异常处理:
Layout Data Binding
处理空数据,当您要提取数据对象并将其传递给视图时,无需检查空对象以防止应用程序崩溃。 - 代码可重用性:如果要在其他
Activities
中使用布局,请使用Layout Data Binding
您只需要将数据变量传递到布局。但是对于Manual Data binding
,您应该为每个java类复制相同的代码,以将变量分配给视图,这将在复杂的视图中产生很多样板代码。
此外,如果您要使用数据绑定替换findViewById()
作为第二种方法,则有一种更好的方法称为View Binding
,您可以详细了解here。
与其直接回答您的2个问题,不如说数据绑定和实时数据的几个关键功能-最终可能会帮助您选择一个而不是另一个。
实时数据类支持转换-此有用的类提供了一种在将实时数据对象分派给观察者之前对其进行更改的方法,或者您可能需要返回其他{ {1}}实例基于另一个实例的值。以下是来自官方android文档的在LiveData
上应用转换的示例示例,
ScheduleViewModel类:ViewModel(){ val userName:LiveData
LiveData
从上面的示例中可以看到-在init {
val result = Repository.userName
userName = Transformations.map(result) { result -> result.value }
} }
对象中,init
对象已使用LiveData
进行了“转换”,然后将其内容分配给“观察者”
数据绑定通常与一组Observable一起使用,并且无法像上面的示例一样在分发之前“转换”正在观察的数据。
Transformations.map
的另一个有用功能是称为LiveData
的类-该子类可以观察其他MediatorLiveData
对象并根据其变化做出反应-通过数据绑定AFAIK,限于特定的“可观察字段”。