I want to load data when user scroll . The loaded data is combine at the end of the ListView.
I test this feature . I found endless scroll in android .But I use this when the user scroll at the end of the list loading still appear and can't click on listitem . How can I know when the data end ?
For example, you could use this code within your getView method:
#Override
public View getView(final int position, View row, final ViewGroup parent) {
...
if (position > lastViewed && position == getCount()-1) {
lastViewed = position;
runTask(); //I immagine an AsyncTask which fetch data from the net or from a local db
}
...
}
Of course in your hypothetical AsyncTask you do not have to clear the adapter on onPreExecute but just adding the new items.
Sorry but the question is a bit too generic, without knowing the stucture of your code it comes complicated to answer, anyway I hope it will help.
Related
I am getting data from Database and displaying using a custom list adapter in a ListView. I need to display only even position items in ListView.
i am able to solve this in two ways.
1. sorting data before attaching to adapter, but i want to do those task in getView() method of adapter/by using other available methods in adapter.
2.
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if( position%2 == 0 ) {
// display
} else {
// not display
}
return view;
in this i am getting alternate view's are empty view's.. i want to avoid these empty view.
i ant to do those all calculations in getView() method, without empty view in the ListView. How i can do this?
I will suggest you to create new List with filtered data and use it in your adapter. Still if you want an alternate solution you can try below code:
#Override
public int getCount() {
int halfCountOfList = itemList.size()/2;
// Add +1 in halfCountOfList if itemList size is odd.
int finalCount = halfCountOfList + itemList.size()%2;
return finalCount;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Item item = getItem(position*2);
//No need to to check for even item
return view;
}
No, just no. This is a really bad idea.
Don't do this. It makes no sense. Think about it: getView() is called because a View for an item is required. It is too late to make any decision about whether this item needs to be displayed in the ListView or not, it already has to be displayed. What you are trying to do is simply not how ListViews and Adapters are supposed to work.
Just filter the List before passing it to the Adapter, you can modify the List while it is being displayed by exposing it through a getter method on the Adapter and then immediately calling notifyDataSetChanged(). Any other solution which deviates from this or tries to make Adapters work like you expect it would just be a brittle hack and should never be used.
PS: Use a RecyclerView instead of a ListView. It's much better.
If you give a ListView adapter a set of data to display, it's going to try to call getView() on all of the data when it's needed - it doesn't discriminate. The decisions on how to display it are made in the getView() function.
The two are options are to either modify the data set, or only provide full-fledged views to your even index-ed values. Unfortunately, there aren't other ways around this.
Make a another list which contains only even position items in it and pass it on adapter. adapter will call getView method for all items present in list.
make another function in adapter
public int getItemViewType(int position) {
// return a value between 0 and (getViewTypeCount - 1)
return position % 2;
}
After that in GetView() method
int viewType = getItemViewType(position);
switch (viewType) {
case 0:
layoutResource = ;//Even Item
break;
case 1:
layoutResource = ;//Odd Item
break;
}
IF Your data will be of some objectType and the database will return
ArrayList<Object>,
then you can do this
Eg:-
ListView lv; // assign this view to some ListView
final List<Object> listResult; //sorted list returned by database
int len = listResult.size();
for (int i = 1; i <= len; i++) {
if (i % 2 == 0){
Object x = listResult.get(i);
//extract the data you need from the object returned
lv.add(x);
}
}
I am integrating endless grid view. end less is working perfect. but on scroll while update my adapter data at that time grid view goes to top. and i need that it should be maintain it's current position where it is.
For the feel adapter in grid view i used below code.
myDataAdapter = new ProductGridAdapter(activity, results, null);
gridView.setAdapter(myDataAdapter);
gridView.invalidate();
myDataAdapter.notifyDataSetChanged();
Can any one tell me that how can i resolve this issue?
Have a variable that captures the top element of your grid view that is being displayed. Then whenever you invalidate the view, use setSelection() function. http://developer.android.com/reference/android/widget/ListView.html#setSelection%28int%29
I got the way. in first time i add adapter in list view and after that i just update the adapter.
if (myDataAdapter == null)
{
myDataAdapter = new ProductGridAdapter(activity, results, null);
gridView.setAdapter(myDataAdapter);
}
else
{
myDataAdapter.updateData(results); //update adapter's data
myDataAdapter.notifyDataSetChanged();
}
I have searched these forums for nearly 3 hours and seen several similar questions but none of the answers works for me.
I have a single Activity, with several card views. One of the card views has a Spinner with string values and a very simple ListView. The user selects a value from the Spinner, between 1 and 12. The ListView should then display a number of strings equal to the value selected, based on the position in the spinner list. For example, user selects 2nd item in spinner list and the ListView displays 2 strings. I have a custom adapter on the listview. The ListView itself initially displays a single row, which is correct. However, after the user selects a value from the spinner, the listview is not displaying the extra rows, it still only displays one row. The data for the ListView comes from an ArrayList. I have checked the data model of the adapter after the user selects a value and it has the correct number of entries, as does the ArrayList itself, yet no matter what I try the ListView itself still only display the first row. I have tried NotifyDataSetChanged and every variation of Invalidate without success.
The various code samples:
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent == spDoseFrequency){
Toast.makeText(this,String.valueOf(position),Toast.LENGTH_SHORT).show();
rebuildReminderTimesList(position + 1);
}
}
private void rebuildReminderTimesList(int numberOfTimes){
Toast.makeText(this,"yup",Toast.LENGTH_SHORT).show();
//reset selected item to position 1
myApp.iSelectedReminderTimeIndex = 0;
//clear array and list, then rebuild with hourly timeslots
iarrTimes = new int[numberOfTimes][2];
liReminderTimes.clear();
int startTime = 8;
for (int i = 0; i < numberOfTimes; i++){
iarrTimes[i][0] = startTime + i;
iarrTimes[i][1] = 0;
liReminderTimes.add(pad(startTime + i) + ":00");
}
//refresh the listview
myAdapter.notifyDataSetChanged();
}
public class ReminderListAdapter extends ArrayAdapter {
List<String> liTimes;
Context ctx;
LayoutInflater inf;
public ReminderListAdapter(Context ctx, List<String> liTimes) {
super(ctx, R.layout.reminder_time_listview, liTimes);
this.liTimes = liTimes;
this.ctx = ctx;
inf = LayoutInflater.from(ctx);
}
public void setLiTimes(List<String> liTimes){
this.liTimes = liTimes;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder viewHolder;
if (view == null){
view = inf.inflate(R.layout.reminder_time_listview,parent,false);
viewHolder = new ViewHolder();
viewHolder.sTime = (TextView) view.findViewById(R.id.tvTime);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.sTime.setText(liTimes.get(position));
return view;
}
private static class ViewHolder{
TextView sTime;
}
}
Any help would be appreciated as this is driving me crazy.
Quick update to this question: I have just tested supplying the initial list more than one value but even then it only displays the first item. Is there perhaps a problem with using ListView inside a CardView object? All my other cards work fine, only the ListView one fails to display properly.
Also, I have tried amending the code so that instead of changing the number of elements in the list, it just changes the text in the string of the first element and this works fine. So the notifyDataSetChanged appears to be working, but it just won't display more than one item. A quick check of the Adapter.getCount() method also gives the correct number of elements back, but won't display them.
A lot of folks forget to do the notifyDataSetChanged() call, but you've got that. Are you using a custom adapter? If so, that makes this sound like an issue with one or more of the adapter's methods. In particular, it sounds like getCount or getView might not be returning what they should be. That could either be because of a flawed logic issue, the underlying data source isn't being updated correctly, or the underlying data source isn't the same object you think it is. Without seeing your adapter though, it's hard to diagnose.
I found the problem. I had several CardView objects inside a LinearLayout, which itself was inside a ScrollView. As soon as I removed the ScrollView, the List inside the Card displayed properly. This has unfortunately created another problem in that I can no longer scroll the page to see later cards, which I have not yet found a solution for, but that is a different topic.
I want to make a listview that as user scroll to bottom of list view other items of list fill automatically from internet.I wrote code to that in the adapter of that expandable list view (within getGroupView() method)as like this,
public View getGroupView(final int arg0, final boolean arg1, View arg2, ViewGroup arg3) {
//if(arg2==null){
//arg2=act.getLayoutInflater().inflate(R.layout.layout_exlistview_group, null);
}
//((TextView)arg2.findViewById(R.id.nameText)).setText(item.getItemName());
if(arg0>=getGroupCount()-1){//chech is near for end
/*here i run a asynctask to download data and add items to SparseArray of this class.That sparsearray is the source to the adapter to view them in listview*/
}
//return arg2;
}
So is this correct way to do this or is there any good way to do that?
From the fact that you're using getGroupView I assume you're using an ExpandableListView, not a regular ListView, which should probably be stated in your question.
Either way, the best way to do this would be to assign a OnScrollListener onto your list and then do your check there, rather than in getGroupView.
I'd recommend you put something along the lines of the following into your onScroll method:
if (firstVisibleItem + visibleItemCount > (totalItemCount - NUM_BEFORE_LOAD)) {
loadMore()
}
where NUM_BEFORE_LOAD based on your example would be 1, but you could make it anything you want to make the list load quicker than when it hits the bottom.
I am trying to do a endless listview with the Commonsware Endless Adapter (https://github.com/commonsguy/cwac-endless), which works fine by default.
What I am trying to do is a basic chat application.
New items should appear at the end and the chat history should be loadable by the endless adapter when the user scrolls to the top.
This by itself is not hard to do. If the ArrayAdapter contains the data s.t. newest items are at position 0, then simply using android:stackFromBottom in the XML declaration of the ListView will put the beginning of the list at the end.
To make sure that the 'load more' inicator is located at the top, I override getItem, getView etc. to provide it with the reversed positions (count-1-position).
My Problem: When the EndlessAdapter adds new data at the end of the List, the "load more" indicator remains visible, causing it to endlessly fetch more data until there is no more to fetch.
Expected is that it loads one batch and the user then needs to scroll down (here:up) to load further elements.
What am I missing?
Personally, I'd consider pull-to-refresh for this scenario, rather than EndlessAdapter.
That being said, if you are seeing additional rows appear, but the pending view is still there, then your modified getView() is not working properly. The additional rows appearing would indicated that notifyDataSetChanged() itself is functioning (otherwise, those rows would not show up). So, if the pending view is still shown, then getView() presumably is returning the pending view (position 0, I'd guess). In fact, I have no idea how you can get a reverse EndlessAdapter to work, as the first row should always be the pending view and should always be loading data, until you run out of data (and, in the case of a chat, that's possibly never the case).
Hence, again, I'd use pull-to-refresh, or you are going to have to switch to a different "endless" scheme that is paying attention to scroll events, rather than just waiting for the pending view to be displayed, as the trigger to fetch more data.
Do not care on notifyDataSetChanged() help.
I implemented an adapter to return Integer.MAX_VALUE as count of elements and especially calculate index in a cache.
Here is some snippet:
<ListView
android:id="#+id/logContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stackFromBottom="true" />
......
logContainer.setOnScrollListener(new OnScrollListener() {
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if ((logAdapter.getCachedCount() - (Integer.MAX_VALUE - firstVisibleItem)) <= LINES_TO_TRIGGER_PRELOAD && !logAdapter.isPreloading()) {
logAdapter.preloadAtBackground();
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
});
class LogAdapter extends BaseAdapter {
private ArrayList<String> logList = new ArrayList<String>();
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView logLineView = new TextView(LogViewDialog.this);
int idx = logList.size() - (Integer.MAX_VALUE - position);
logLineView.setText(logList.get(idx));
return logLineView;
}
.........