我一直在开发一款带有数据绑定功能的应用程序。 MVVM。
我正在尝试在横向模式下为我的应用使用替代布局。我有:
layout/fragment_content.xml
layout-land/fragment_content.xml
两种布局都具有不同外观的相同视图,并从相同的视图模型获取提要,如下所示:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data class="MyBinding">
<variable
name="viewModel"
type="com.myapp.package.viewModel.VMFirst"/>
<variable
name="controlModel"
type="com.myapp.package.viewModel.VMSecond"/>
</data>
<DIFFERENT CONTENT HERE>
两种布局都存在所有视图和ID。
嗯,问题是,它没有编译,错误只是"cannot find symbol method getViewModel"
而另一个变量是getter。
到目前为止我尝试了什么:
使用布局和布局 - 土地文件夹(失败,错误在上面解释)
使用我在此处Use Layout Aliases找到的布局别名Issue 199344: Data binding does not work with layout aliases。尝试这种方法时,我没有更改xml文件中的任何内容。这也失败了,错误是Could not write to com.myapp.package.databinding.MyBinding
是否无法在多个布局文件中使用数据绑定data
标记?在使用数据绑定时,我应该使用什么来为不同的状态使用不同的布局?谢谢!
修改:删除class="MyBinding"
并未更改错误。
答案 0 :(得分:1)
我在我的应用程序中大量使用MVVM,并且还围绕它构建了一个库。
我遵循惯例,即每个XML中都有一个ViewModel。此外,viewmodel变量的名称在所有XML中都是相同的。
因此,在您的情况下,您可以创建另一个包含VMFirst
和VMSecond
的ViewModel类。
public class ParentVM {
VMFirst first;
VMSecond second;
}
XML(纵向和横向)都具有相同的名称,例如activity_main.xml
。
<layout>
<data>
<variable
type="ParentViewModel"
name="vm"/>
</data>
然后在MainActivity代码中不需要检查。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewDataBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setVariable(BR.vm, new ParentViewModel());
}
这很有效。
事实上,因为我在所有xmls中都遵循相同的变量名,所以我能够将绑定逻辑包含在基类MvvmActivity
本身中。所以,我的所有活动都是:
public class MainActivity extends MvvmActivity {
@NonNull
@Override
protected ViewModel createViewModel() {
return new MainViewModel();
}
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
}
MvvmActivity实施:MvvmActivity.java
保持常量数据绑定变量的另一个好处是,您可以使用XML本身设置RecyclerView或ViewPager适配器。有关详细信息,请参阅Setup RecyclerView from XML。
答案 1 :(得分:1)
如果有人搜索此问题,两年后我尝试做同样的事情,发现现在一切正常。
我在activity_main
和layout
下创建了一个布局文件layout_sw600dp
。以下是layout
资源下的布局:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<variable
name="small_variable"
type="Integer"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/myRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="@+id/small_square"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@android:color/holo_blue_bright"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
这是layout_sw600dp
文件夹下的布局:
<?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"
xmlns:tools="http://schemas.android.com/tools">
<variable
name="big_variable"
type="Long"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/myRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="@+id/big_square"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@android:color/holo_blue_bright"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
两者都有一个视图,但每个视图都有不同的ID:small_square
和big_square
。
我在手机和平板电脑上运行该项目。这是我的发现:
myRoot
是不能为空的视图,而big_square
和small_square
是可以为空的视图。变量是否可以为空,无论它们是否存在于所有布局中(这是预期行为)。MainBinding
,或者如果您未默认定义为LayoutResourceName
+ Binding
)。small_variable
和small_square
在代码方面是binding.smallVariable
和binding.smallSquare
。binding.bigSquare?.operation
之类的视图,这很好,您无需事先检查它是平板电脑还是手机,或者视图是否为空。binding
字段。您仍然可以对代码说binding.smallVariable = 3
,它将完成分配并保存值。我认为要小心一点。答案 2 :(得分:0)
默认情况下,将根据布局文件的名称生成Binding类,将其转换为Pascal大小写和后缀&#34; Binding&#34;它。上面的布局文件是main_activity.xml,因此generate类是MainActivityBinding。 - Binding Data
并在编译时生成。
所以,用java代码选择不同的布局。
layout/
R.layout.activity_main
R.layout.activity_main_tablet
values/
<bool name="is_mobile">true</bool>
<bool name="is_tablet">false</bool>
values-w820dp/
<bool name="is_mobile">false</bool>
<bool name="is_tablet">true</bool>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getResources().getBoolean(R.bool.is_mobile)) {
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
} else {
ActivityMainTabletBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main_tablet);
}
}