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:
Using layout and layout-land folders ( Failed, error is explained above )
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.
Data Binding allows you to effortlessly communicate across views and data sources. This pattern is important for many Android designs, including model view ViewModel (MVVM), which is currently one of the most common Android architecture patterns.
Recently Android has announced that with Kotlin 1.4. 20, their Android Kotlin Extensions Gradle plugin will be deprecated and will no longer be shipped in the future Kotlin releases. Android Kotlin Extensions plugin brought with it two very cool features : Synthetics let you replace calls to findViewById with kotlinx.
View binding and data binding both generate binding classes that you can use to reference views directly. However, view binding is intended to handle simpler use cases and provides the following benefits over data binding: Faster compilation: View binding requires no annotation processing, so compile times are faster.
If anyone searches for this question, after 2 years I tried to do the same, and I saw it's working all fine now.
I created a layout file activity_main
under layout
and layout_sw600dp
. Here's the layout under layout
resources:
<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>
This one is the layout under layout_sw600dp
folder:
<?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>
Both has a view but it has different id in each: small_square
and big_square
.
I run the project on phone & tablet. Here are my findings:
myRoot
is not a nullable view when using binding from Kotlin, while big_square
and small_square
are nullable views. Variables are nullable whether or not they exists in all layouts ( which is expected behaviour ).MainBinding
in above examples, or if you don't define it LayoutResourceName
+ Binding
by default ).small_variable
& small_square
was binding.smallVariable
and binding.smallSquare
on code side.binding.bigSquare?.operation
, which is great that you don't need to check if it's tablet or phone or view is null or not beforehand.binding
fields even if layout that they are in won't be used. You can still say binding.smallVariable = 3
on code and it'll do the assignment and save the value. I think it's good to be careful.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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With