It turns out that the problem was much simpler than I had originally thought.
The Problem
It was actually two fold. The scroll listener for some reason fires the change event as soon as the gridview’s adapter is set even when there are no items in it. My scroll listener was something like this:
private AbsListView.OnScrollListener mOnScrollListener = new AbsListView.OnScrollListener({ @Override public void onScrollStateChanged (AbsListView view, int scrollState) {} @Override public void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if ((firstVisibleItem + lastVisibleItem) >= totalItemCount && !mAsyncTasksPending) { loadMore(); } } });
The above code ended up calling the loadMore();
even before the gridview’s adapter was loaded with the first page results from the service. That ended up making two requests wastefully. The second problem is because of how I had declared the loadMore();
method. I use AndroidAnnotations to reduce boilerplate code. I annotated loadMore();
with @Background
to execute the service request in a background thread to prevent the UI from locking up. But, I didn’t need to do this since I was already taking care that the service request be executed in a background thread using another library called async-http, which by the way is freaking awesome! My guess is, when I set the method to be executed in a background thread it was holding up the gridview’s listener thread somehow which caused the events to accumulate in the call stack. This would probably explain why when I paused the activity and resumed it, it would function normally and the moment I scrolled it and caused it to call loadMore()
it would freeze again and none of the callbacks would fire.
A little more than the solution
First, what I ended up doing was removing the redundant @Background
annotation from loadMore();
. Then, I realized that my activity was a little bloated. So, I created a fragment and shoved the gridview, and managing its adapter into the fragment. I was then able to keep my activity lean. By doing so, I have also opened up the possibility of introducing additional fragments to handle different views if necessary in the future which makes this all the more easy to manage without bloating my activity.
Next, I updated the gridview’s onScroll
callback. It was still being called as soon as the adapter was set in the gridview. Initially, the adapter is empty and I don’t want it to call loadMore();
when the first page results haven’t been filled in the adapter yet. Loading the first page is handled through the list navigation listener since that sets the currently selected item for which I then go and fetch the list of images. So now, this is how my updated OnScrollListener
looks.
private AbsListView.OnScrollListener mOnScrollListener = new AbsListView.OnScrollListener({ @Override public void onScrollStateChanged (AbsListView view, int scrollState) {} @Override public void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //only load more if the visibleItemCount is > 0, and the user has reached the last row of visible items if (visibleItemCount > 0 && ((firstVisibleItem + lastVisibleItem) >= totalItemCount) && !mAsyncTasksPending) { loadMore(); } } });
One thought on “[UPDATE] Weird problem with GridView OnScrollListener and list navigation listener”