How to set SwipeRefreshLayout refreshing property using android data binding?

daneejela picture daneejela · Dec 4, 2016 · Viewed 15.8k times · Source

I am using android data binding library. If I want to make a view visible I can write something like this:

<TextView
            android:id="@+id/label_status"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="@{habitListViewModel.message}"
            app:visibility="@{habitListViewModel.hasError ? View.VISIBLE : View.GONE}" />

Is there an option to bind to a refresh property of swipeRefreshLayout in a similar (xml) way?

Currently I am setting it in code by calling setRefreshing(true/false) but would love to make it in xml to be consistent.

Answer

Entreco picture Entreco · Apr 18, 2017

No need to hack. The key is to look for the public methods in SwipeRefreshLayout documentation. In general, Databinding will look for the corresponding name without the set part. E.g. you'll find there:

The OnRefreshListener

Since OnRefreshListener is a public interface, with a single method, you can directly use this in your binding, like so:

app:onRefreshListener="@{() -> viewModel.onRefresh()}"

Updating the Status

For this one, you use the other public method, which translates to:

app:refreshing="@{viewModel.isLoading}"

All together, it can look something like this:

<data>
    <variable name="viewModel" type="ViewModel" />
</data>
<android.support.v4.widget.SwipeRefreshLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:refreshing="@{viewModel.isLoading}"
    app:onRefreshListener="@{() -> viewModel.onRefresh()}">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"          
        android:layout_height="match_parent" />

</android.support.v4.widget.SwipeRefreshLayout>

viewmodel - kotlin :

class ViewModel(
        private val provider: DataProvider
    ) : DataProvider.Callback {

    /* isLoading - Needs to be public for Databinding! */
    val isLoading = ObservableBoolean()

    /* onRefresh() - Needs to be public for Databinding! */
    fun onRefresh() {
        isLoading.set(true)
        provider.fetch(this)
    }

    fun onReady() = isLoading.set(false)

    fun onError(oops: Exception) = isLoading.set(false)
}

viewmodel - java:

public class ViewModel implements DataProvider.Callback {
    public ObservableBoolean isLoading = new ObservableBoolean();
    private DataProvider provider;

    MasterViewModel(@NonNull final DataProvider provider) {
        this.provider = provider;
    }

    /* Needs to be public for Databinding */
    public void onRefresh() {
        isLoading.set(true);
        provider.fetch(this);
    }

    public void onReady(List results){
        isLoading.set(false);
    } 

    public void onError(Exception oops){
        isLoading.set(false);
        Log.e("Stack", oops);
    }
}