Observing LiveData with DataBinding after ViewStub inflation - android

I am trying to delay inflating some views in a large fragment to avoid a freeze.
in fragment.xml :
<?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="vm"
type="exm.ViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- some other views -->
<ViewStub
android:id="#+id/fragment_stub"
android:inflatedId="#+id/fragment_content"
android:layout="#layout/fragment_stub_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:vm="#{vm}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_stub_content.xml:
<?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">
<data>
<variable
name="vm"
type="exm.ViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ACustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#{()->vm.toggleDetails()}"
app:isExpanded="#{vm.canShowDetails}"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Function toggleDetails in vm toggles boolean livedata canShowDetails. I can see that this function is successfully called by a log. But canShowDetails (A MutableLiveData<Boolean>) does not change despite being observed in a view. A trivial code would be fragment_stub?.inflate() in my Fragment's onViewCreated() which is called successfully.

Related

Way to do two-way data binding in Android while using <include> tag?

So the problem space is pretty simple.
I have a layout. Let's call it fragment1.xml and it looks like this.
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="viewModel"
type="SomeViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/include_some_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
layout="#layout/layout_consent_checkbox"
app:checkedData="#{viewModel.checkedData}" />
</LinearLayout>
</layout>
And let layout file layout_consent_checkbox.xml be this.
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="checkedData"
type="Boolean" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="#+id/cb_some_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="#={checkedData}"
android:text="Plis check this?"/>
</LinearLayout>
</layout>
Now according to my knowledge, this should work. checkedData in SomeViewModel should be updating the Boolean value, based on the status change of the CheckBox. But it isn't getting updated. Please have a look and update me on what I'm doing wrong. Thanks!

Can't pass viewmodel in databinding to child include layout

this is some code in my parent xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="(..).viewmodels.TestViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:theme="#style/AppTheme.AppBarOverlay"
>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<include
android:id="#+id/layout"
bind:viewModel="#{viewModel}"
layout="#layout/test_content"/>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Here's the child include layout
<layout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="(..).TestViewModel" />
</data>
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
tools:layout_editor_absoluteX="74dp"
tools:layout_editor_absoluteY="1dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/disable"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#color/orange"
android:text="#{viewModel.buttonText}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</layout>
As you can see in this example I data binded text to the viewmodel and passed it down from parent to child via bind:viewModel="#{viewModel}"
Here's the code in the activity:
val binding:TestContentBinding = DataBindingUtil.setContentView(this, R.layout.test_content)
binding.setLifecycleOwner(this)
binding.viewModel = testViewModel
If I set the binding to the child xml then the data gets binded, however if i set the binding to the parent activity the viewmodel doesn't get passed down.
The back end certainly has the correct data however I don't know how to bind data to the child.
I've even tried manually setting the layout's viewModel however that doesn't work. How do I pass the viewmodel?
You could try changing the name of the variable in your included layout.
Here is a quick article explaining how to use include layout with ViewModel.

How to pass data variable to included layout?

Is there a way to pass data variable to included layout?
parent layout
<?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"
tools:showIn="#layout/fragment_settings">
<data>
<variable
name="viewModel"
type="......settings.SettingsFragmentViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:overScrollMode="never"
android:padding="#dimen/spacing_default">
<include
android:id="#+id/main"
layout="#layout/layout_settings_main" />
</androidx.constraintlayout.widget.ConstraintLayout>
and want to have viewModel in included 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"
tools:showIn="#layout/fragment_settings">
<data>
<variable
name="viewModel"
type="......settings.SettingsFragmentViewModel" />
</data>
<merge>
...........
or is it possible only when setting like this:
binding = FragmentSettingsBinding.inflate(inflater, container, false).apply {
lifecycleOwner = this#SettingsFragment
viewModel = this#SettingsFragment.viewModel
main.viewModel = this#SettingsFragment.viewModel
}
In parent xml inside include tag pass data variable to included layout using bind:viewModel.
<?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"
xmlns:bind="http://schemas.android.com/apk/res-auto"
tools:showIn="#layout/fragment_settings">
<data>
<variable
name="viewModel"
type="......settings.SettingsFragmentViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:overScrollMode="never"
android:padding="#dimen/spacing_default">
<include
android:id="#+id/main"
layout="#layout/layout_settings_main"
bind:viewModel="#{viewModel}" />
</androidx.constraintlayout.widget.ConstraintLayout>
Your included layout will get object instance in viewModel.
For more details check this tutorial
Open build.grade and add dataBinding { enabled = true } in block android{ // ...}
Ok so, at the beginning of this article I’ve said that it depends whether it’s possible to pass the variable to a secondary layout or not. The reason for this is the following:
Data binding does not support include as a direct child of a merge element. For example, the following layout is not supported:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="user" type="it.communikein.myunimib.User"/>
</data>
<merge>
<include layout="#layout/name"
bind:user="#{user}"/>
<include layout="#layout/contact"
bind:user="#{user}"/>
</merge>
</layout>

Android Conductor - fitsSystemWindows does not work on first controller

With my most recent app, I've decided to use Conductor for the whole of the navigation. It's a single activity app, and everything works fine, except for the splash screen - for some reason, the initial controller refuses to stretch under the status bar, even though the main layout and the controller host are both CoordinatorLayouts with appropriate fitsSystemWindows flags.
The host activity:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="net.fonix232.app.viewmodel.MainViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:fitsSystemWindows="true">
<net.fonix232.app.common.ChangeHandlerCoordinatorLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
The splash controller's layout:
<?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">
<data>
<variable
name="viewModel"
type="net.fonix232.app.viewmodel.SplashViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:fitsSystemWindows="true">
[... splash content ...]
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The screen after splash:
<?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">
<data>
<variable
name="viewModel"
type="net.fonix232.app.viewmodel.SplashLandingViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:fitsSystemWindows="true">
[... splash landing content ...]
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The first splash layout does not stretch the content (a custom image layer setup) under the status bar, however on the second splash (SplashLanding) screen, it is properly stretched - and since I use shared element transition, I get a nice image resize effect on the background as well.
Where is this going wrong?

android-integrate databinding with BottomSheet

while integrating the BottomSheet we need to make the parent layout as the CoordinatorLayout but in databinding we use <layout>. While implementing this it throws an exception :-
Caused by: java.lang.IllegalArgumentException: The view is not a child of CoordinatorLayout.
How to integrate BottomSheet with databinding
<layout>
<data>
<import type="android.view.View" />
<variable
name="cabLayoutBinder"
type="newage.com.hopin.rideBooking.CabSelectActivity" />
<variable
name="modelBinder"
type="newage.com.hopin.rideBooking.model.DataBinders" />
<variable
name="fareSetters"
type="newage.com.hopin.rideBooking.model.FareDetails" />
</data>
<android.support.design.widget.CoordinatorLayout
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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".rideBooking.CabSelectActivity">
</android.support.design.widget.CoordinatorLayout>
</layout>
You put context in your coordinator, but in databinding you don't implement this way.
Try to remove this line and try again:
tools:context=".rideBooking.CabSelectActivity"
Let me know if it worked.
This is how I am using it
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".com.abc.Activity">
<data>
<variable
name="viewModel"
type=".com.abc.ViewModel" />
</data>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
layout="#layout/toolbar" />
</FrameLayout>
<!-- Adding bottom sheet after main content -->
<include layout="#layout/bottom_sheet" />
</android.support.design.widget.CoordinatorLayout>
</layout>

Categories

Resources