I am using Recyclerview to load contacts in my android app. Each row has a contact number Textview and a username Textview. Contacts load from local database but usernames should load from remote server. I have tried loading usernames for each contact in onBindViewHolder method but its get stuck whenever I scroll fast.
#Override
public void onBindViewHolder(final ContactsAdapter.ContactsViewHolder holder, final int position) {
final ContactInfo current = cDataset.get(position);
//Here I load from remote server...
}
So I want to load usernames in advance while scrolling like Endless recyclerview. Is it possible to implement this?
I am not sure I got exactly what you are saying, but it seems like you want to load all data before loading it to your recyclerView.
instead of loading from remote server on onBindViewHolder, you can load it in advance either in your Activity or Fragment and pass it to your adapter...
Don't put the get call in your onBindViewHolder, you should already have your data by now.
Either obtain your data via a call prior to initializing your Adapter or if you still need to get the data from inside the Adapter, put that call within a background thread, though you are likely to run into problems there as well if you scroll fast.
Let's say that you load items in chunks of size of 30. Add OnScrollListener on your RecyclerView. Every time you pass some threshold, for example, 20 out of 30 items, you initiate fetching the next chunk of 30 items, and, once you have them, put them at the and of the RecyclerView.
Play with this numbers. Instead of 30 and 20, you may try 100 and 50, or 50 and 10. Find numbers for which you have the best UX. However, do not count that user will always have prepared next set of data, so keep one circular ProgressBar at the end of RecyclerView as long as you have more data to load.
Another approach which you may try is to periodically start a service that will fetch all required data, prepare everything the way it is required for UI, and cache it in memory or in DB.
Related
I have a backend API endpoint which returns JSON in some sets. Each set contain 10 lines of Json.
For example:
curl http://www.something.com?getData=0 will give first 10 elements and curl http://www.something.com?getData=1 will return next set and so on.
I am using RecyclerView and StaggeredGridView to load data from given endpoints. Right now I am only fetching first set and it's working perfectly fine.
What I am looking for?
How can I load data in RecyclerView as per screen sizes in Android. FOr example:
Let's say device hdpi can able to load 25 staggeredGridViewin RecyclerView. So , here the endpoints request in sequence:
http://www.something.com?getData=0 // will fetch 0-10
http://www.something.com?getData=10 // will fetch 11-20
http://www.something.com?getData=10&skip=5 // will fetch 21-25
How can I make above process dynamically. So that it will work for all screen sizes?
BTW this is how I am loading the data into StaggeredGridView adapter:
mRecyclerView = (RecyclerView) mActivity.findViewById(R.id.staggering_grid);
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
mAdapter = new StaggeredGridAdapter(mContext);
mAdapter.addItems(response);
mRecyclerView.setAdapter(mAdapter);
Possible Solution
If I got to know that How much Grid I need to fill according to device then I can simply make a request till I get the data to fill expected number.
I can also use Event Bus to send notification to Retrofit to make another call till device screen filled.
Is it good approach? If yes then How can I achieve it?
what you can do is load data in excess say 50 at a time instead of 10, that way you have enough data to populate the whole display, if your api only lets you get 10 items per request, then you fire multiple requests from different threads and add them to your adapter, and refresh the view once all the requests were done successfully. So this way you wont be needed to request for all the items and have enough items for display in any device screen setting
this is obviously too much data to display in an android app.. what can i do to mitigate this problem ?
I tried to show all 10000 rows in a list view but i got poor performance. I also tried to display all 10000 rows of data in the list view but that just made it slow
Why do you need that method ? WS method's approach is wrong. First of all, you must change method signature like this (int pageNumber, int recordNumber ) and make pagination enabled. If you use a listview, you can show the first 10 record. Then, if the user need more than that, could click to show more button.
As the title says, I'm using a BaseAdapter to display items in a ListView. Obviously a ListView will reuse views, including TextViews and NetworkImageViews.
Assuming 3 items can be displayed at once, the NetworkImageView will be reused for items at index: 1, 4, 7, ....
Depending on what's being displayed, the NetworkImageView will either:
request the image from the Network and display it,
display a cached Bitmap,
or display a local drawable resource.
Items 2 and 3 work fine, however in Scenario 1, let's say we're displaying item at index 4 from the network, and the user scrolls to item 7 before 4 is loaded and it's a local resource, we display the local resource. However our network image request may just be finishing now, so we end up displaying an incorrect image.
How can I enforce the proper (expected)behavior?
The answer from #Snicolas is spot on, but lacks some pointers on how to actually accomplish that. So here goes.
The general idea is to keep track of the ongoing image requests for every row. That way, when you encounter a recycled row, you can cancel the pending request and kick off a new one for the new data relevant to that row.
One straightforward way to accomplish that is to make the ImageContainer that you can get back when requesting an image load, part of the adapter's ViewHolder/RowWrapper. If you're not using this pattern yet, you should. Plenty of examples out there, including a good I/O talk.
Once you've added the ImageContainer to your holder, make an image request and store the container that you get back. Somewhat like this:
ImageListener listener = ImageLoader.getImageListener(holder.imageview, defaultImageResId, errorImageResId);
holder.mImageContainer = ImageLoader.get(url, listener);
The next time a recycled row comes in the adapter's getView() method, you can get your holder back from it and check wether it has a ImageContainer set. One of the following 3 scenarios may apply:
There is no ImageContainer, which means you're good to go to make a new image request.
There is an ImageContainer and the url that it is loading is the same as for the new row data. In this case you don't have to do anything, since it's already loading the image you're after.
There is an ImageContainer but the url that it is loading is different from the new row data. In this case, cancel the request and make a new one for the current row data.
If you like, you can move some of this logic by having your BaseAdapter extension implement AbsListView.RecyclerListener (and set the adapter as recycler listener for the ListView or GridView). The onMovedToScrapHeap(View view) method gets passed in the view that has just been recycled, which means you can cancel any pending image requests in there.
You don't need to enforce anything if you use the provided NetworkImageView.
NetworkImageView detects when it has been recycled and cancels the request automatically.
I don't know this API but my guess is that you should cancel any pending request before recycling such a view. How you can do that I can't say.
Did you here of alternatives like :
picasso ?
robospice UI Module ?
In my application I am fetching the data from a web service in XML format, and parsing it and showing the data in listview. The problem is that if the web service contains 5000 objects then it takes a lot of time to display the data.
Can it be possible to show some data in listview and fetch the data at the same time at the end of the list.
Please provide me some sample code.
If you use convertView in your ListAdapter´s getView method it should not matter how many items you have in the list since the Views are beeing reused.
If your Listadapter takes an array of som sort you could add items to the array continuosly and call
mListAdapter.notifyDataSetChanged();
every time new data is added to the list.
By Using AsyncTask you can do this easily as each object is being fetched can be shown in listview using publishProgress() method while also updating user about what percentage of data hasbeen loaded.
Update:
By the way according to your situation the tool below which is developed by commonsware https://stackoverflow.com/users/115145/commonsware will suits you best...
https://github.com/commonsguy/cwac-endless
cwac-endless: Provides the EndlessAdapter, a wrapper for an existing ListAdapter that adds "endless list" capability. When the user scrolls to the bottom of the list, if there is more data for this list to be retrieved, your code gets invoked in a background thread to fetch the new rows, which then get seamlessly attached to the bottom of the list.
Currently, I'm using AsyncTask to handle Http connection and retrieve data as JSON format.
Loading all data is trivial but it consumes too much time, so I decided to switch to load 10 items at a time using LIMIT OFFSET (mysql).
Next I set up the event onScroll for my list view to create a new AsyncTask each time user scroll. However, from what I read, AsyncTask is stored in a thread pool which is limited 5 threads at a time, so I'm not sure this is a right approach. I'm newbie to client/server app, so could I anyone give me an advice on this issue? Any related article, documentation would be greatly appreciated.
Here are few useful links for it,
Android: Implementing progressbar and "loading..." for Endless List like Android Market
Endless Listview with current Async Task
Android Endless List
http://www.androidguys.com/2009/10/21/tutorial-autogrowing-listview/
http://mylifewithandroid.blogspot.com/2010/03/progressively-loading-listviews.html
In simple steps,
As user scrolls – detect the end of the list 1)Display a progress
notification 2)Ask for update 3)Receive update (asynchronously) and
extend list
A typical approach would be e.g. to load 25 initially and then have a footer in the list that displays e.g. the current count and the total count and upon pressing loads another 25 and so on. That would be a paged sort of loading.
When you do that you have to keep the current position and notify the adapter that the list has changed.
If you are using a ListView, I believe I can safely assume that you must be using some sort of ListAdapter. Instead of starting a new AsyncTask in the onScroll event, you should maintain just one single AsyncTask to retrieve data from the server, add that data to the ListAdapter dataset and then call notifyDatasetChanged on the ListAdapter.
The ListAdapter and ListView will take care of the rest.