I have a custom adapter which inherits from BaseAdapter, and I have a ListView in a different .java file. Basically I click on a button and this calls the custom adapter. So when the app first loads the fist time I click the button, it's fine. On every subsequent click the items (retaining order) are duplicated both the number and the contents of the items. I am sure there is something wrong with the overridden getView method:
public View getView(int position, View convertView, ViewGroup parent) {}
However I am not sure whether the View convertView is set to anything on when the items are ready to be displayed in the ListView. So I put a check in there:
if (view == null) {}
I think this check is the root of the problem.
Any help will be appreciated.
Here is the gist to the SharedResourcesAdapter, the custom adapter class:
https://gist.github.com/serceberka/f34c8f3339ef9e4bc9dc23d3ac8f74c4
Here is the gist to the SharedResources AppCompatActivity where the adapter gets set:
https://gist.github.com/serceberka/ea9fc73b42a9d271e6fbac7d7793667f
(You'll find it in the PageLoad class which extends AsyncTask)
The issue has been resolved.
Basically there was no problem with the custom adapter itself, the issue was that I was reading the items from a List and updating the List every time a new query was sent. To fix the problem I cleared the List before a adding items to it to avoid getting duplicated items (i.e. from the same search query) or retaining items from previous queries.
Related
i use ListView to display a list of 30 products.
protected class ListProductAdapter extends ArrayAdapter<Product>
implements View.OnClickListener {
...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
I noticed that when I display the activity, it first calls getView 6 times, then if I scroll down, getView will be called to display other products, but if then I scroll up, getView is called again on product for which getView had already been called. Isn't it possible to get it in memory to not have to recalculate everything I scroll down and up ?
The ListView recycles its Views precisely so you do not have to have a View for every item in memory all the time, but it passes an old View as convertView so it can be reused and doesn't have to be re-inflated every time. See here.
That's how ListView works. It manages a number of views and calls getView(int, View, ViewGroup) whenever it needs one view to be set up. It doesn't hold to many views though. You might be able to hold all in memory, but that's not its intent.
If convertView is null the list needs you to create the views (your first 6 calls to getView). When you start scrolling, the list will provide you with an (already initialized) convertView which you only need to refill with the data you want to display.
See the documentation of getView for an elaborate explanation.
I have a ListView with a custom adapter, displaying information from a database.
When I start the app, the data is read from the database, given to the adapter, which is then attached to the ListView. A LayoutAnimationController is run on the ListView, displaying the contents smoothly.
this._lvList = (ListView)_v.findViewById(R.id.lvList);
this._lvList.setAdapter(new TableAdapter(getActivity(),R.layout.tablerow,Category.getCategories()));
LayoutAnimationController lac = new LayoutAnimationController(AnimationUtils.loadAnimation(getActivity(), R.anim.slide_in_left));
lac.setDelay(0.2f);
this._lvList.setLayoutAnimation(lac);
this._lvList.startLayoutAnimation();
No problem at all.
Now when I click on any entry of the ListView, the entries which were not clicked disappear, the clicked entry becomes the one and only entry in the list and is displayed at the top, as expected.
View v;
for(int i = 0;i<_lvList.getChildCount();i++) {
v = this._lvList.getChildAt(i);
if(v!=clickedView) {
Animation animSlideOut = AnimationUtils.loadAnimation(getActivity(), i%2==0?R.anim.slide_out_left:R.anim.slide_out_right);
animSlideOut.setStartOffset(i*50);
// some more stuff
}
v.startAnimation(animSlideOut);
}
This works as well, but now the problem, if I click again on that single list entry, I want the list to repopulate, displaying all items again.
I thought I could use the code from the start (the first snippet), as it works fine when starting the app, but...this time...it doesn't. No animation happening. The reason is, there are no views to animate in my ListView (except the one from the previous step).
Instead of creating a new Tableadapter I already tried to clear it, fill it new, called notifyDataSetChanged()... no use, as
_lvList.getChildCount();
stills returns 1 view, while the adapter holds all 18 entries.
I as well tried
requestLayout();
forceLayout();
invalidate();
invalidateViews();
to force the ListView to generate its child views before the animation, but it's not working. So atm the ListView just appears instantly, somewhen after my call to the layout animation.
Summary : my ListView contains no child views before the start of the layout animation, how can I force it to generate them?
Thx in advance :)
Hmm... have you done this yet? (below)
in your custom adapter, override the method:
#Override
public View getView(int position, View convertView, ViewGroup parent){
//the position of the item, the convertView is the view layout of what that row is
}
to change how the listview is updated. this getView method gets called by Android every once a while to refresh the view (you don't call it manually)
also, i think you only need to call
listView.notifiyDataSetChanged() and listView.invalidate() to force the update, after you repopulate the list
you can read more on listviews here:
http://www.vogella.com/articles/AndroidListView/article.html
http://developer.android.com/guide/topics/ui/layout/listview.html
I am trying to set item selected in OnItemClick event in ListView and it just wouldn't leave item selected. What am I doing wrong?
lView.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(#SuppressWarnings("rawtypes") AdapterView parent, View clickedview, int position, long id)
{
clickedview.setSelected(true);
mItemsAdapter.select(position);
}
});
few things:
1. I am trying to implement Multiple Select on the list View.
2. I cannot extend from ListActivity because Activity extends from BaseActivity custom class already.
3. mItemsAdapter is a custom ItemsAdapter adapter that extends BaseAdapter.
4. I don't need a checkbox in there, just to be able to see the row selected is fine.
5. ItemsAdapter overrides getView() and sets the layout of the row by inflating xml
I could manage to get an item of a ListView to be set as selected when long-clicked:
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
parent.requestFocusFromTouch(); // IMPORTANT!
parent.setSelection(position);
return true;
}
It only worked after I called requestFocusFromTouch().
I currently don't have much time. So I'll take a look again later this day.
Anyway take a look at my previous questions, I was struggling with the same:
Change ListView background - strange behaviour
Clickable ListView
In case the solution for you is not in there (I think it's in the first one) we will need more code, in order to help you.
Hope this helps a bit.
I have not had much luck using the built in functionality for selection.
I see you have your own custom adapter, which I am guessing means your inflating custom views as rows. If your row has anything more then a checkedtextview I don't think you will be able to correctly use setSelections.
I solved this problem by using my own models and functions. Each item in the list had data with it to determine it if was selected or not. I could then iterate though that array, toggle selections with and and even update the UI by changing values and calling notifydatasetchanged on the adapter (which used getView and checked against my selection model to draw checks).
I have a ListActivity which gets its data from a database query. I also have a custom adapter which extends simple cursor adapter.
To show the customised content, I have overridden the newView and bindView methods.
Each element of the view has:
TextView containing a title
ImageView containing number of stars - the image shown is changed based on a value obtained from the database
A button - the button text changes on clicks (Favourite/Make Favourite), and triggers a database update event.
My problem is this - when I scroll the ListView, the changes I made seem to disappear .. for instance, the first item is marked favourite, and the list is scrolled ... when I come back to the first item, the text reverts back to its previous value, although internally the db has been updated.
I read that the notifyDatasetChanged() is not right for this case as the adapter should be notified of the database changes. I am trying to use the reQuery() method, but do not know where to place it.
Should I place the reQuery() in the onClick method of the button? If not, where should it be placed?
What so ever Adapter is you are using must have getView Method.. Whenever a list is scrolled this getView Method got called for all the listItem in the view. Make Sure in the getView Method. That the view is getting generated dynamically.
It should check for clicked or changed value.
to update the list without scrolling your have to call listView.getAdapter().notifyDataSetChanged()
Check the following link. here i mentioned a complete code to use listview properly. Using this we can achieve any listview behavior. We can embed animation also.
Change ListView background - strange behaviour
Hope this help :)
If you have extended BaseAdapter ,
after data is changed call , listView.setAdapter() and in getView() , update the view's data too.
Use SetListAdapter with ArrayAdapter to display the list. Use ConvertView to avoid inflating View.
if (convertView==null)
{
//inflate your list
}
Basically, I want to be able to use two ListViews through my BaseAdapter class in the same activity. The ListViews will be displayed side-by-side and each item within the ListView will contain multiple views (ImageView, TextView, etc.).
My main issue is retreiving/displaying data through the getView() method inherited from BaseAdapter. How would I go about detecting which ListView is being updated through this method so I will know which code to call/update? I've tried looking at the ViewGroup parameter in getView() hoping that it led me to the parent of the ListItem but the id it returns was different from my ListView's resource ID...in fact it wasn't even in my R.java file at all:
12-14 04:44:58.613: ERROR/ParentFromGetView(312): 16908298
12-14 04:44:58.623: ERROR/MyListViewId(312): 2131165191
I was hoping to do something like so:
public View getView(int position, View convertView, ViewGroup parent) {
if (parent.getId() == R.id.ListView1) {
//Do stuff
} else if (parent.getId() == R.id.ListView2) {
//Do different stuff
}
}
...but the Ids are drastically off as seen above.
Thanks in advance!
You cannot share a ListAdapter between two ListViews.
Well, I would like for them both to run on the same activity.
So?
Currently I'm extending my activity as a ListActivity and I set my adapter accordingly.
That only affects one of the two ListViews, whichever one has the #android:id/list value. You need to create a second ListAdapter for use with the second ListView. You get the second ListView by calling findViewById(), and you associate the adapter with that ListView via setAdapter().