Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Too many XML data bindings

I made a View that I want to reuse across many pages. It contains feedback elements for the user such as a ProgressBar, TextView etc.

Due to high amount of items within, binding all those turns out like this:

<layout ... >

    <data>
        <variable
            name="screenObserver"
            type="my.namespace.ScreenStateObserver" />
    </data>


    <androidx.constraintlayout.widget.ConstraintLayout ... >

        <my.namespace.view.ScreenStateView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:loading="@{screenObserver.isProgressVisible}"
            app:errorText="@{screenObserver.errorTxt}"
            app:buttonText="@{screenObserver.errorBtnTxt}"
            app:errorVisible="@{screenObserver.isTextVisible}"
            app:buttonVisible="@{screenObserver.isButtonVisible}"
            app:onButtonClick="@{() -> screenObserver.onErrorResolve()}" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

I find copy/pasting the whole XML block messy and error-prone. Is there any way to make this simpler ?

ScreenStateObserver is just a interface that I implement in my ViewModel and bind as follows:

override fun onCreateView(...): View? {

    val factory = InjectorUtils.provideViewModelFactory()
    viewmodel = ViewModelProviders.of(this, factory).get(MyViewModel::class.java)
    binding = MyFragmentBinding.inflate(inflater, container, false).apply {
        screenObserver = viewmodel
    }
}
class AtoZViewModel() : ViewModel(), ScreenStateObserver { ... }
interface ScreenStateObserver {
    val isProgressVisible : MutableLiveData<Boolean>
    val isTextVisible : MutableLiveData<Boolean>
    val isButtonVisible : MutableLiveData<Boolean>

    // [..]
}

Thanks !

like image 755
JonZarate Avatar asked Jul 24 '26 12:07

JonZarate


1 Answers

Here is my suggestion to reduce code.
First declare a class like this

interface ScreenState {

    class Loading : ScreenState

    class Error(val errorMessage: String, val errorButtonText: String) : ScreenState
}

and inside you CustomView it will be

internal class ScreenStateView {

    fun setState(state: ScreenState) {
        if (state is ScreenState.Loading) {
            // show loading
        } else {
            // hide loading
        }

        if (state is ScreenState.Error) {
            //show {state.errorMessage} and {state.errorButtonText}
        } else {
            // hide error
        }
    }
}

using in xml

    <my.namespace.view.ScreenStateView
        ...
        app:state="@{screenObserver.screenState}"
        ...
        app:onButtonClick="@{() -> screenObserver.onErrorResolve()}" /> // for onButtonClick I think it still better if we keep like this

Hope it help

like image 164
Linh Avatar answered Jul 27 '26 03:07

Linh