Android DataBinding & MVVM - Using same layout files for different conditions using same view models

匿名 (未验证) 提交于 2019-12-03 02:47:02

问题:

I've been developing an app with data binding & MVVM.

I'm trying to use an alternative layout for my app on landscape mode. I have:

layout/fragment_content.xml layout-land/fragment_content.xml 

Both layouts have same views with different look, and get feeds from same view models, like this:

<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> 

All the views and id's exist in both layouts.

Well, problem is, it doesn't compile, error is simply "cannot find symbol method getViewModel" and getter for the other variable.

What I tried so far:

  1. Using layout and layout-land folders ( Failed, error is explained above )

  2. Using layout aliases Use Layout Aliases which I found here Issue 199344: Data binding does not work with layout aliases. I didn't change anything in xml files while trying this approach. This also failed, error is Could not write to com.myapp.package.databinding.MyBinding

Is it not possible to use data binding data tag in multiple layout files ? What should I use to use different layouts for different states while using data binding ? Thanks !

Edit: deleting class="MyBinding" did not change errors.

回答1:

I heavily use MVVM in my apps and am also building a library around it.

I follow the convention that there is a single ViewModel in every XML. Also, the name of the viewmodel variable is same in all XMLs.

So, in your case, you can create another ViewModel class that contains VMFirst and VMSecond.

public class ParentVM {    VMFirst first;    VMSecond second; } 

Both the XMLs (portrait and landscape) will have same names, say activity_main.xml.

<layout>     <data>       <variable            type="ParentViewModel"           name="vm"/>     </data> 

Then no check is required in MainActivity code.

protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);      ViewDataBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);     binding.setVariable(BR.vm, new ParentViewModel()); } 

This works.

Advantages of single ViewModel

In fact, because I follow same variable name throughout all xmls, I am able to include the binding logic in a base class MvvmActivity itself. So, all my activities look like:

public class MainActivity extends MvvmActivity {      @NonNull     @Override     protected ViewModel createViewModel() {         return new MainViewModel();     }      @Override     protected int getLayoutId() {         return R.layout.activity_main;     } } 

MvvmActivity implementation: MvvmActivity.java

Another advantage of keeping a constant data binding variable is that you can setup RecyclerView or ViewPager adapters in XML itself. See Setup RecyclerView from XML for more details.



回答2:

By default, a Binding class will be generated based on the name of the layout file, converting it to Pascal case and suffixing "Binding" to it. The above layout file was main_activity.xml so the generate class was MainActivityBinding. --Binding Data

and generated at compile time.

so, select different layout by java code.

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);        }  } 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!