Explanation of the getView() method of an ArrayAdapter - java

Could you explain the getView() method of an ArrayAdapter.
I read the docs and it has three parameters:
position: The position of the item within the adapter's data set of
the item whose view we want.
convertView: The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view.
Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see getViewTypeCount() and getItemViewType(int)).
parent: The parent that this view will eventually be attached to
I understood the position parameter. Like they said, it's imply the position of the item, who view has been requested.
Where does convertView come from. I've seen many examples where they check if convertView is null. If is is null, they inflate a new instance of the row layout, populate it and return it. I guess I've gotten my head around that too but one thing still baffles me. What is the layout that is passed in through the convertView parameter. Is if the resource parameter that is passed in when initialising the ArrayAdapter? Is is a cached copy of the last layout returned by getView()?
And lastly. What does the parent parameter do. I haven't seen too many examples utilising this. Most of them simply reuse/inflate a row layout and return it.
(I'm asking because I have an on-click animation in my ListView. Specifically this one that aims to replicate Spotify's dropdown quick action menu. My animation has been a little sluggish. After diagnosing this issue for a while, I've realized that this has been due to the fact that my getView() method takes a bit of time to complete as I'm inflating a fresh row layout in every iteration. Someone suggested caching the row layout in a ViewHolder while other examples point to reusing the convertView parameter i.e. only inflating a row layout if convertView is null.)

Is is a cached copy of the last layout returned by getView()?
The convertView is the view of a row that left the screen(so it isn't the last view returned by the getView method). For example, the list is first shown, in this case convertView is null, no row view was previously built and left the screen. If you scroll down, row 0 will leave the screen(will not be visible anymore), when that happens the ListView may choose to keep that view in a cache to later use it(this makes sense, as the rows of a ListView generally have the same layout with only the data being different). The reason to keep some views in a cache and later use them is because the getView method could be called a lot of times(each time the user scrolls up/down and new rows appear on the screen). If each time the row view would need to be recreated this would have resulted in a lot of objects being created which is something to avoid. In your getView method you would check convertView to see if it is null. If it's null then you must build a new row view and populate it with data, if it isn't null, the ListView has offered you a previous view. Having this previous view means you don't need to build a new row layout, instead you must populate it with the correct data, as that cached view has the old data still attached to it(you would see a lot of questions on stackoverflow where users ask why the rows of their ListView are duplicating when they scroll down).
What does the parent parameter do. I haven't seen too many examples
utilising this. Most of them simply reuse/inflate a row layout and
return it.
It should be used to get the correct LayoutParams for the newly inflated/built row. For example, if you inflate a layout which has a RelativeLayout as the root and you don't use the parent to get the LayoutParams you could have some problems with the row layout. To take the parent in consideration you would use :
convertView = getLayoutInflater().inflate(R.layout.row_layout, parent, false);

My understanding of convertView is that it's essentially views that have been recycled because they're not being used at the moment - for example, you scroll down the list, the ones at the top aren't on the screen, so they get passed into this parameter for use when you need a new view (so you don't have to create a whole new one while having unused ones sitting around idle). iOS has a similar method called dequeueReusableCellWithIdentifier. If each row of your listview has the same structure, it's safe to cast this to the appropriate type and just update the information in it - text, images, etc. It will be a View that was previously returned by a getView() call for the same list.
My best guess (and it is admittedly a guess) with parent is that it's the view that this adapter's list is a child of. It gives you a route back to the rendering system if you need a context, access to the resource system, to pass information to or receive information from the list's parent view.

Related

Java android baseAdapter set list item one time

Hello i have a fully working code for my list adapter:
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.overview_item, null);
//getting id's
TextView name =(TextView)vi.findViewById(R.id.userUsername);
TextView date =(TextView)vi.findViewById(R.id.imageDate);
ImageView image=(ImageView)vi.findViewById(R.id.userImage);
ImageView avatar=(ImageView)vi.findViewById(R.id.userAvatar);
//setting text
name.setText(dataNames.get(position));
date.setText(dataDates.get(position));
//set image
Log.d("test: ", "Adapter wants to get picture");
imageLoader.DisplayImage(dataImage.get(position), image);
imageLoader.DisplayImage(dataAvatars.get(position), avatar);
return vi;
}
This code works perfect but the problem is this function runs everytime when you scroll throught the listview so whenever the lis item is getting in sight. And that's not what i want. i want it to do this function just once for every list item. This is because when your scrolling fast trought the list it has to load all images again so the loading image is showing and it keeps jumping because the loading image is another size then the image wich is getting loaded. I hope thay tou understand my question and can help me. Already thanks and if i'm not clear please ask my anything in the comments.
So short:
How do i run this code just once for every list-item and not everytime when it's getting in sight?
Your code might call findViewById() frequently during the scrolling of ListView, which can slow down performance. Even when the Adapter returns an inflated view for recycling, you still need to look up the elements and update them. A way around repeated use of findViewById() is to use the "view holder" design pattern.
Check this links:
1 - http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html
No, you should not. This is the way ListView works. Beside, you should use ViewHolder pattern for better performance.
If you still want to do this, you could remove check NULL with convertView. It will solve your problem, but lead to performance, I think.

Multi-level ExpandableListView in Android

I'm trying to create a category tree from a given unknown-size nor level list of categories. So I'm trying to create a general expandable list which can contain 2+ number of levels.
The general idea is to add to every child who has childs another ExpandableListView in it's layout. The problem is that the second level wont open, it looks like it rendered it over the child or something. Here's some screen-shots of the result:
Here's how it's look like before opening
And after opening the first option: (It's supposed to be empty)
And now open the second one: (Has 4 childs and one of them have childs of his own)
As you can see the third option looks like it's been rendered another option or something on it, after clicking to open it:
It's does nothing except change the state of the arrow. At least it tries to open it...
Here's the code:
CatAdapter.java: (extends BaseExpandableListAdapter)
http://pastebin.com/6yUTkMbJ
Category.java:
http://pastebin.com/E7yWwpna
catitem.xml:
http://pastebin.com/G5MPT3Ua
The usage:
http://pastebin.com/Wk0FqJhn
Sorry for the long question, I was trying to be clear as possible.
Thanks in advance! Sorry for my bad english!
Edit:
I ended up making a custom view for this task, thank you all for your answers!
I believe the problem is in your getChildView() method:
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
convertView = inflater.inflate(R.layout.catitem, parent, false);
TextView textView_catName = (TextView)convertView.findViewById(R.id.textView_catName);
Category current = categories.get(groupPosition).childs.get(childPosition);
textView_catName.setText(groupPosition + " , " + childPosition);
if(current.childs.size() > 0 ) {
ExpandableListView elv = new ExpandableListView(context);
elv.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.WRAP_CONTENT, AbsListView.LayoutParams.WRAP_CONTENT));
elv.setAdapter(new CatAdapter(context, current.childs));
((ViewGroup)convertView).addView(elv);
}
return convertView;
}
When you encounter an 'expandable' child, you are still inflating R.layout.catitem and adding your new elv to it. Since the catitem is a RelativeLayout and you don't add any parameters for alignment, each view is placed at the top-left corner, overlaying whatever else is there.
You may want to try changing R.layout.catitem to have a vertical LinearLayout as its root. This should prevent them from overlapping the child's title, but I can't guarantee that the children's children will not still overlap. It's an easy change, though, and worth a shot.
Also, from the docs for ExpandableListView:
Note: You cannot use the value wrap_content for the android:layout_height attribute of a ExpandableListView in XML if the parent's size is also not strictly specified (for example, if the parent were ScrollView you could not specify wrap_content since it also can be any length. However, you can use wrap_content if the ExpandableListView parent has a specific size, such as 100 pixels.
That says "in XML", so I'm not sure if it means to apply to code or not. It seems to me that they'd use the same mechanism, so it might be worth looking into. I'm not sure how you'd go about setting a maximum size for the parent. You may be able to measure the size of one item, and multiply by the number of children. You'd have to take margins/separators into account, so it may not be simple.
If that doesn't work, you may need to roll your own ViewGroup directly. It shouldn't be too hard to implement it from scratch, just don't forget to try to take advantage of view recycling(which your current method doesn't do anyway).
I was have same situation where I had to use ExpandableList and at each level I needed to have groupPosition and childPosition but using multi-level ExpandableList, It was not possible to get accurate groupPosition at second level data. So that, I used another approach. I have given a demo link which I used in a project.
1) In this library, you need to bind parent child relation in advance before you bind your actual data.
2) In your Layout, top most layout must be LinearLayout. Please refer header.xml, groups.xml and childs.xml in demo link.
Demo Link: MultiLevelTreeView
Thanks.

List Adapter and getView function explanation

I'm thoroughly confused about the life cycle of list view. More specifically, what does the list adapter do exactly? Does it just provide data to the given view? And when/where does the getView() function gets called? And what purpose does this getView() function provide? From just looking at the code, it looks like getView() is "assigning" data to the view to be displayed. I'd like to be able to use list views without having to memorize, do this and then this in order for it to work. I'd much rather understand it so I can use it properly. Someone please help me understand all of this.
Also, if someone can explain to me.. what's the difference between BaseAdapter and ArrayAdapter? and any other kind of adapters that comes with Android.
What I have understood is your adapter constructor instantiated by activity and then on activity launch the getView() method is called. the {#param position, view, viewGroup}
position: it refers to the position of the view as given by adapter. Please Note it is different from the position in {OnItemClick(AdapterView adapter, View v, int position,long id)} here position is the list item position. The {position} in {getView()} changes after particular object in the list are displayed again for eg. when you scroll.
view: the view here is the view you want to be presented through getView(). It can be a particular XML layout for each row. So this states clearly that getView is called to plot every row. this view needs to be valid one or another layout (LinearLayout by default) will be selected to maintain uniqueness.
viewgroup: as you might know and as name says will be the container of your #param:view
any other point is appreciated.
getView() fills in the data into the item's view with the given index. The view which is given as a parameter may be a pre-inflated view. If it is not, you have to infalte it yourself.
An ArrayAdapter simply calls setText on the given view with the result of toString() of the object with the respective index from the array. If you override it, you can do more complex stuff, like assigning a picture or filling in more TextViews.
I recommend the following tutorial: http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/
Hi list adaper provides view for listview.
when user scrolls listview at that time getview is called.
getview is used to populate your view with data hence the name adapter.
The Adapter does all the "rember to do this" for you. If you change a list view's backing data structure through the adapter's methods (e.g. "add()") it will fire all the datachanged and update events you'll need for the list view to show the new state of the data.

Creating xml template for feed/list items in Android?

I'm helping a friend create an android app that will have screens with lists of info similar to a feed. I've been learning xml layout in Android and have some of the basics down, but don't have a lot of familiarity with doing the java stuff. I've successfully created includes to seperate layout files for compontents within a screen, but what I'm wondering is if such a component can be used as a kind of template for feed/list items that get inserted programmatically on the back end. IE, is there a way to have Android create a list and for each list item it uses the external xml as a template? Sorry if this is somewhat vague, I'm new to this and trying to understand what our options are. TIA!
Yes, every list item can be a custom layout. In fact you always have to define a layout for the list entries. You can either choose a prebuilt one from android.R.layout or you can use your own from R.layout. You can specify it when you create the list adapter in code.
Have a look at one of the ArrayAdapter constructors for example:
public ArrayAdapter (Context context, int resource, int
textViewResourceId)
Since: API Level 1 Constructor Parameters
context - the current context.
resource - The resource ID for a layout file containing a
layout to use when instantiating views.
textViewResourceId - The id of the TextView within the layout resource to be populated
The constructor takes a layout that will be used for the ListView childs. Works similar with other adapters.
What you usually do is inflating the layout inside getView() of the adapter though. When you did that, fill all the data you need into the views of the layout, and return the view.
Note that you get an argument called convertView. This is one of the older layouts you already inflated before. In most cases the user just scrolled down and that entry is not visible anymore. If this convertView is not null, you can fill your data in there instead of inflating the whole layout again (thats expensive).
You can find a working example inside the
ANDROID_SDK\samples\android-10\ApiDemos\src\com\example\android\apis\view\List5.java file. Also take a look at the other list examples in that folder.

Android: create a listview that covers half the screen and updates itself

I'm writing an app in which you enter a few letters and it creates a list of words that use those letters in that order (but not necessarily consecutively).
I would like my listview to only take up the screen underneath the text entry field and two buttons (the text field and buttons are in a linearLayout and on the top of the screen not taking up much room).
Also, I have an arrayList of all the words I want to show in the list but I don't know how to make it update with the new arrayList each time the search function is invoked.
Thanks for any help.
Also may you might want to check out adding a header to the list view... something like...
lv = getListView();
LayoutInflater inflater = getLayoutInflater();
ViewGroup header = (ViewGroup) inflater.inflate(R.layout.myheader,
lv, false);
lv.addHeaderView(header, null, false);
Maybe put your first LinearLayout (the small form) and the ListView in a second LinearLayout (vertical).
Then for your data, you can use an ArrayAdapter (or extend it but it seems like your list item layout should be simple so no need really) to link your array to the ListView, and you should be able to find adequate methods in that class among : notifyDataSetChanged(), getFilter(), various methods to update the inner adapter ArrayList etc.

Categories