Android - load more items when grid view has reached the end - android

I'm making an app and I'm using grid view to show all of my images, the problem is I have lots of images, about 12,000, and I don't want to load all of them at the start, because lets face it, it will take forever, so I was wondering what is the best way of accessing the server to fetch more items once the gridview has reached the end.
Thanks.

To achieve load more items on scrolled to end of the gridview
gridView.setOnScrollListener(new AbsListView.OnScrollListener(){
#Override
public void onScroll(AbsListView view,
int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
//Algorithm to check if the last item is visible or not
final int lastItem = firstVisibleItem + visibleItemCount;
if(lastItem == totalItemCount){
// here you have reached end of list, load more data
fetchMoreItems();
}
}
#Override
public void onScrollStateChanged(AbsListView view,int scrollState) {
//blank, not required in your case
}
});

One way is to start the server request for an image in the adapter getView(). When the request completes, you set the retrieved bitmap on the ImageView. There is a very in-depth description of this technique on the Android Developer Blog: Multithreading For Performance | Android Developers Blog. Most servers are fast enough that the lag time to display the image is not objectionable.
However, if you want to load images before the ImageViews are displayed, here's another way you can do it with an OnScrollListener, an AsyncTask, and a list adapter for the `GridView.
Say you have a constant final int THRESHOLD = 50; and a variable lastItem that starts at zero.
When user displays your GridView the AsyncTask kicks off and retrieves the first 100 images. In the onPostExecute(), it adds the images to your adapter and calls notifyDataSetChanged(). It also adds 100 to lastItem.
So now your adapter has 100 images. The user is scrolling through images and the OnScrollListener gets called.
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
if (firstVisibleItem >= lastItem - THRESHOLD) {
new FetchImageAsyncTask().execute();
}
}
Your AsyncTask executes, lastItem is updated to 200, and your adapter gets 100 more images.
Then the user scrolls some more and it starts all over again.
By using the threshold, the user can scroll another 50 images before the end of the list, and that may be enough time to load the next 100 images.

Related

Track impression of items in an android ListView

I have a ListView and an ArrayAdapter < CustomListViewItem > set as its adapter. I would like to track number of impressions of each CustomListViewItem item.
Whenever a ListView item comes into view that should count as one impression. When it goes out of view and then again comes into view the impression count increments. When user scrolls, some items will go out of the view and some will come into view. I want to track the items which both come into view and move out of view.
What i tried:
One thing i tried was to setOnScrollListener for the list
view and do tracking in the
onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) callback.
I can use firstVisibleItem and visibleItemCount to do the job.
In the documentation it says that this is called when the scroll has completed. But it seems to be getting called a lot of times when the scrolling is slow. Probably after each pixel of scroll. This is making the scroll very laggy.
Is there any other way to do this? By using some kind of callback which gets called for each item when it goes out of view or comes into view?
I searched a lot on web and didn't see any posts related to such kind of tracking.
I couldn't find another way to do this. So, i optimized what i was already doing. I thought i should share this as it may help someone else.
I use firstVisibleItem and visibleItemCount of onScroll()
callback only. I use two variables to keep information of previous onScroll() callback. They are :
prevVisibleStart and prevVisibleEnd
Lets take an example to understand the algorithm.
Assume initially that after first onScroll()
firstVisibleItem = 0
and
visibleItemCount = 3 => lastVisibleItem = 2
These are used to set my previous visible states.
So, prevVisibleStart = firstVisibleItem = 3
and prevVisibleEnd = firstVisibleItem + visibleItemCount - 1 = 2
Now if i scroll down, i will always have
firstVisibleItem >= prevVisibleStart
and
lastVisibleItem >= prevVisibleEnd
So, if the previous range was 0 to 2. The new range would be somewhat like 1 to 3. Since, i have already considered 0 to 2 for impression. I will only consider 3 as new impression. The reason being the views 1, 2 are still in view and they hadn't gone out of view. So, a new impression is not counted for these. This effectively gives the correct range to consider for impressions as well as reduces the range for checking as well.
Similarly, this can be done for scrolling up.
Assume that the current visible items are 2-4.
Now after scroling up the range becomes (say)1-3. This means that 1 has come into view. So, count an impression for this view. This way the number of operations in onScroll() significantly reduce.
Sample code follows
range [i-j) is considered for impression.
private static int prevVisibleStart=-1;
private static int prevVisibleEnd=-1;
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if(prevVisibleStart <= firstVisibleItem) {
// scroll down
i = Math.max(firstVisibleItem, prevVisibleEnd + 1);
j = firstVisibleItem + visibleItemCount;
} else {
// scroll up
i = firstVisibleItem;
j = Math.min(prevVisibleStart, firstVisibleItem + visibleItemCount);
}
prevVisibleStart = firstVisibleItem;
prevVisibleEnd = firstVisibleItem + visibleItemCount - 1;
// now can use [i-j) to update impressions
}

How to understand firstVisibleItem and visibleItemCount in onScroll method?

I have gridview listing 9 items per page, and when user scrolls it should load 9 more. But i cannot set it properly, i am struggling with this code:
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if((firstVisibleItem + visibleItemCount) == totalItemCount)
{
load_more();
}
}
});
I am not sure what to put on calculation line, so to give me 9 by 9 as user scrolls. I tried different calculations, but without success, sometimes it just loads automatically couple of times, sometimes infinite. How to accomplish what I need?
There is a nice library which exactly does what you need.
https://github.com/shontauro/android-pulltorefresh-and-loadmore
Sample
((LoadMoreListView) getListView())
.setOnLoadMoreListener(new OnLoadMoreListener() {
public void onLoadMore() {
// Do the work to load more items at the end of list here
}
});
There are more options available in the library, you can try that as well.
For actually implementing for yourself, its quite difficult to do on onScroll. I too gave up and implemented through different procedure.

How to implement scroll in list view to implement pagination?

I am building an application like techcrunch.
I am fetching data from server in JSON format and displaying the data in list view like article title,author name and image.
I have applied pagination means when user scroll more articles load in a list view. My pagination works fine but there is an issue in the scroll function as the fresh or new data loads the scroll dose not aligns with the data.
To clarify more in simple words my scroll-er goes at the top of the page when i am actually scrolling down
this is my code :
listView.setOnScrollListener(new AbsListView.OnScrollListener()
{
#Override
public void onScrollStateChanged(AbsListView absListView, int i)
{
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
int lastItem = firstVisibleItem + visibleItemCount;
if(lastItem == totalItemCount){
if (mPreLast != lastItem)
{
mPreLast = lastItem;
onStart();
}
}
}
});`
You can use:
listView.setSelectionFromTop(newPosition, 0);
With this method you can set the position to a ListView, using the first parameter as the new position on the list, and the second parameter can be used to set the distance from the top

Android NSFetchedResultsController

I have an iPhone and an Android app. On iPhone I use NSFetchedResultsController to manage the data I have for my UITableView's. Currently I have a lot of data (several thousands of rows).
On my Android app i'm using ORMLite and i'm storing the data into a table, but when I fetch, i'm pulling out all data into an array and using ArrayAdapters. Is there a more efficient way to do this such as an NSFetchedResultsController type object? I want to only load the objects needed, rather than all of them for performance reasons.
Is there a way to do this within ORMLite? I tried to find in the documentation but found nothing so far... Is there anything else I'm missing that would be of help here?
You could use CursorAdapter.
See http://developer.android.com/reference/android/widget/CursorAdapter.html
and http://www.mysamplecode.com/2012/07/android-listview-cursoradapter-sqlite.html
or you could implement an Endless Adapter
Lazy Loading might help here.
Lets presume you have a data of 10000 entries. You could display a finite subset of this say 90 entries at a time.You could initially load a few entries say 30(1-30). On scrolling to the end you load 30 more entries.As soon as the no.of entries loaded reaches 90 (on the third load) you could truncate the current dataset as 31-120 instead of the previous 1-90.
The same goes the other way too i.e on scrolling upwards.
int offset=0;
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
final int MAX_SUBSET=90;
final int INTERVAL=30;
#Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}
#Override
public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
final int lastItem = firstVisibleItem + visibleItemCount;
if(lastItem == totalItemCount) {
//Load new data and update The adapter.
if(totalItemCount<=MAX_SUBSET){
loadData(0,totalItemCount+INTERVAL);
}
else{
offset+=INTERVAL;
loadData(offset,MAX_SUBSET);
}
}
else if(0==firstVisibleItem){
//Load old data
if(totalItemCount<=MAX_SUBSET){
loadData(0,totalItemCount+INTERVAL);
}
else{
offset-=INTERVAL;
loadData(offset,MAX_SUBSET);
}
}
});
Ps: I have missed out a few boundary checks but hope you get the general idea.

Binding onScrolling listener to the android ListView

just wanted to ask is there a possibility to bind some listener to the ListView scroll event.
What I would like to achieve is that once ListView have been scrolled to the bottom I would like to ask server for more data if any is there.
I know that there is a function like: getLastVisiblePosition() but I assume it must bu used in some kind of listener in order to compare with currently last visible position, am I right ?
cheers,
/Marcin
Just to extrapolate on TomTo's answer, some thoughts on how you might do this (theoretical, I haven't tried this in practice):
ListView lv = (ListView)findViewById(R.id.list_view);
lv.setOnScrollListener(new OnScrollListener() {
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
//Check if the last view is visible
if (++firstVisibleItem + visibleItemCount > totalItemCount) {
//load more content
}
}
});
Since firstVisibleItem is returns an index (0-based), I increment by one to get the actual item number. Then, if that, plus the number of visible items, is greater than the total number of items, then in theory the last view should be visible. Shouldn't be a problem, but keep in mind this isn't called till the scrolling is finished.
used
if (++visibleItemCount > totalItemCount)
instead
if (++firstVisibleItem + visibleItemCount > totalItemCount)
AbsListView.OnScrollListener ?

Categories

Resources