Benjamin Basmaci
Benjamin Basmaci

Reputation: 2557

Stop SwipeRefreshLayout refresh animation, despite setRefresh(false)/isRefreshing=false

I'm using SwipeRefreshLayout to refresh my activity. Layout looks like this, very simple:

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <androidx.core.widget.NestedScrollView
            android:id="@+id/feedBase"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        <LinearLayout
                android:id="@+id/linearLayoutFeed"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"/>
    </androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

The linearLayoutFeed gets some views added programmatically on refresh, with data loaded online. When the process is finished, I call isRefreshing=false (the Java equivalent would be setRefreshing(false). This seems like the only way to stop it and that's also what is suggested in other questions. However, this does not work.

The refresh indicator never disappears. I've checked the debugger and the operation finishes and the callback to isRefreshing=false is called. After that, I've checked the value for isRefreshing and it correctly shows false.

This is the (simplified) code I run:

swipeRefreshLayout.setOnRefreshListener {
        loadData() { // callback
            (context as AppCompatActivity).runOnUiThread {
                swipeRefreshLayout.isRefreshing = false
            }
        }
    }

private fun loadData(callback: () -> Unit) {
    Thread {
        try {
            // loading my data
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            callback.invoke()
        }
    }.start()
}

And this is basically what I have read in other questions/answers on here and on other sites. However, the documentation for setRefreshing states:

Notify the widget that refresh state has changed. Do not call this when refresh is triggered by a swipe gesture.

I have looked for other functions to call to end the refresh or to just not set refreshing but I didn't find any other means and neither did not setting it work.

Now for the complicated part:

The SwipeRefreshLayout is set into a ViewPager with a TabLayout. The SwipeRefreshLayout is only on the first page. Now, when I refresh it the first time, the refresh indicator won't disappear. But when I switch pages to the last page and then back to the first and I refresh, the refresh indicator disappears after its finished.

So basically

I don't quite understand that behavior and would like any help to find out what is going wrong here. I don't think I change anything with the page switch that should change the behavior of the SwipeRefreshLayout, but somehow it does.

Edit

Answering the questions in the comments:

Edit 2

I just noticed that, while this error occurs, I can keep swiping. While the first refresh indicator still stays in place, a second one behind it appears and disappears as it should.

Upvotes: 4

Views: 2133

Answers (1)

Benjamin Basmaci
Benjamin Basmaci

Reputation: 2557

Looks like I had some basics wrong or at the very least, had the wrong understanding of how my activity/layout/views are built up.

The reason the loading indicator didn't disappear was, that it actually did. One of them did at least.

I thought I have one SwipeRefreshLayout, however there were actually two! But I deactivated only one of them.

My custom View I had inflating the Layout was itself a SwipeRefreshLayout. So I thought I had this hierarchy:

SwipeRefreshLayout
->NestedScrollView
-->LinearLayout

But I actually had this hierarchy:

SwipeRefreshLayout (View itself)
->SwipeRefreshLayout (from Layout)
-->NestedScrollView
--->LinearLayout

So what I did was stop the refresh of the SwipeRefreshLayout I inflated from the view and not the one of the view itself. So the obvious fix was to remove SwipeRefreshLayout from the layout file and manage the view itself accordingly.

That being said, I still don't understand why the documentation said

Notify the widget that refresh state has changed. Do not call this when refresh is triggered by a swipe gesture.

This kind of gave me the wrong idea of where the problem lies.

Also, I still don't quite understand why this only occurred once and then didn't occur again when I swiped back and forth, as described above. I assume its because the view itself didn't redraw the refresh indicator when it was re-focused, even though it was still "active". So it was there but invisible and just didn't get refreshed/redrawn. Not sure about that though.

Upvotes: 1

Related Questions