what's exactly happening in getView - android

I see this a lot in Adapter extensions override of getView:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.whatever, null);
}
I get semantically what's happening - "if convertView is null then inflate it", but I don't really understand why - what circumstance would convertView be null, and in what circumstance would it already be a View?
Also (and I know "1 question per post"), but as it relates to the above - what's exactly happens during the inflate method? I know what it does generally ("inflates" a view resource to be parsed and populated), but don't fully grok it...
TYIA

AFAIK, this is how getView works.
Suppose you have a list with 50 items and you can only see 5 items at a time. The getView will be called 5 times initially and the convertView will be null for each row and a new row should be inflated.
As you scroll through the list the getView will be called again as the next rows get visible on the screen. Now since 5 rows are already rendered for the list, these rows will be recycled by updating existing rows with new values to show new rows. At this case the convertView will not be null.

Say your list adapter has 1000 objects. Each object is represented by a view. On the phone screen there's place only for maybe some 10 such views. You scroll the list wanting to see more items. Some items go out of sight because you're scrolling. It makes no sense for the Framework to create more views as they will be exactly the same as those which have just gone out of sight. Framework thus can reuse some views it created before and so it offers to you such a possibility by offering you a non-null convertView.
During the inflate method a View object gets created out of some XML resource. The XML resource has a description of a View sufficient for that View to be created and so the inflate method does that creation. So no view - you create a new one by inflating, there is a view already - you can reuse it (you don't have to but you should)

for full information i recommend you to watch this video
it will tell you alot of information include what is happening in getView()

Related

Extending BaseAdapter, when does the view become null?

public class CustomAdapter extends BaseAdapter
I found a code that extends BaseAdapter
public View getView(int index, View view, final ViewGroup parent) {
if (view == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
view = inflater.inflate(R.layout.single_list_item, parent, false);
}
}
TextView textView = (TextView) view.findViewById(R.id.tv_string_data);
textView.setText(dataModel.getName());
my question is when view == null ?
why we need the code if (view == null) {}
thanks
A ListView typically contain more data then the number of displayed rows. If the user scrolls the list then rows and their associated Views will be scrolled out of the visible area. The Java objects which represents the rows can be reused for newly visible rows.
If Android determines that a View which represents a row is not visible anymore it allows the getView() method to reuse it via the convertView parameter.
A performance optimized adapter assigns the new data to the convertView. This avoids inflating an XML file and creating new Java objects.
In case no View is available for reuse, Android will pass null to the convertView parameter. Therefore the adapter implementation need to check for this.
For the first item in the listView the View will be null. It needs to be inflated for the first item.
Please be free to ask any further doubts.
Android re-cycles View objects to minimize object creation and memory usage. The View that is passed to you will either be null, in which case you are expected to create it, or the view will be non-null which means it has been re-cycled. Re-cycled views are ones that you may have created earlier, but can now be used for a different purpose.
A good example of this is a listview. A list may have many elements, say 100. The screen however may only display 10 items of the list. Thus when you scroll the screen, views that were for items no longer on the screen may be passed to you for re-use. This is re-cycling.
For list view we have to provide view for each and every item, and also we have to fill contents also. In most cases the same view will be repeated in every item with different content. So at the first time in getView method we will check, if view is null then we should inflate a view and fill the contents and return. At second time the view will not be null. So you can reuse or provide different view.

Android:Problems with listview when I scroll the list and is disordered

I have an adapter for a ListView which dynamically gets relative layouts to display images and text loaded into the Adapter.
The problem is that when I scroll in its entirety, the Listview is ordered incorrectly. I tried using ViewHolder but that has not solved the problem.
I wonder if there is any other way to do it. Or integer Listview load without execute code that once adapter has already been loaded list.
The main problem is that the images of the other RelativeLayout layouts appear in the wrong list.
Now The problem I have now is that when you scroll through the list slowly shows fine, but if the scroll in the list is fast elements are dislodged. As if not process fast enough position parameter. public View getView(int position, View convertView, ViewGroup parent)
Check your ListAdapter's getView(); make sure that if convertView is null that you are creating it. In both cases you want to update convertView with new data, otherwise you'll have these issues (as Android will recycle those views but not update them).

Do I need to config ConvertView properties if it is not null?

In a custom adapter, how to know weither I need to reconfig the convertView or not?
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = (ImageView) mInflater.inflate(R.layout.avatar, parent, false);
// Should this 2 lines of code be here ?
User user = mUserList.getUserAt(position);
user.setAvatar(imageView);
} else {
imageView = (ImageView) convertView;
}
// or here ?
User user = mUserList.getUserAt(position);
user.setAvatar(imageView);
return imageView;
}
I would think that if it is recycled, I would not need to reset the user's avatar but I often see the configuration happening outside of the if block. Why is that?
I always configure the view outside of if block. This convertView that you get in the getView method might (and most probably will) be set up for another user by some previous call to getView because of ListView's policy to reuse item views when they go offscreen. If you do not set up a proper avatar you will have wrong one for this item. Of course you won't need to reset properties that are independent of the concrete position like background.
For example CursorAdapter separates getView into two parts: newView, that performs inflate and (mostly) position-independent setup and bindView that assigns actual position-dependent data.
It may also happen that you will get exactly the same view that you used for this position earlier. Of course you can avoid resetting a view in this case, but you need to check if data in this view are valid. Setting and then checking View's tag comes to my mind as a most obvious solution.
It is not truly recycled, it just means that you need to fill a "recycled" view with new data according to the its new position. If you don't do it this row will be filled with old data that shouln't be visible on the screen anymore since you scrolled away its position.
So in short you have to reconfigure view with fresh data each time getView() called (outside of if block in your code).
Your issue is only with the understanding of listview.
So here I'll make you clear how it works??
Let's say listview has to contain 20 items but your current screen can accommodate(show on screen) only 8 items(list items, in your case imageview).
When the listview tried to get items for 1----8th it will return you convertView as null because no recycling of objects happened yet.
but, when you try to scroll, in our case(scroll up!).
the 1st element of the list will be recycled when go out of screen, and will be supplied as convertView for 9th item.
In this way listview has to manage only 8th(in our case) to show any number of items.
The opposite will happen if we will scroll down wards.
So, on the basis of convert view (null or not) you have to design your logic either to create and fill or to fill.
Hope this will help you.

Listview duplicates value

I have dynamic listview in which textview and edittext are two columns. The textview comes with proper data but when i insert the value in edittext in first row then i scroll down the list and in third row the edittext is fill with the first row edittext value. I don't know why this happening. Please help me.
Please provide some code so we can better understand the problem. From what i understand this is whats happening.
The adapter generates as many views as can be accomodated on the screen. When you scroll down the list, a new item needs to be generated. This can be done in two ways inside the getView() method shown below.
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
//inflater is the layout inflater for the custom view
convertView=inflater.inflate(R.layout.list_row, null);
return convertView;
}
else{
return convertView; //recycled view
}
}
convertView is the view that just went off the screen and is available for recycling. In your case its the convertView which was supposed to be destroyed but is reused again. So the edit text values reappear in the view below.
I guess it's because you're inflating a layout for items with have concrete IDs (manually set) and android may think that all listview's items are the same
But if you want real help, paste some code and layouts here... We're not fortune-tellers

Cause onClick of a ListView row to offer editing options

I'd like to have the effect of clicking on a row in a ListView and offering buttons to do basic editing with what I'm displaying in said row.
Now I don't mean to change a textview into an editable-textview exactly, rather something that just offers buttons like "edit" and "delete" for example. This could be done with a popup but I'm trying to avoid this, I want these action buttons to be replacing the displayed content of that row.
At first I figured it could just have two layouts for inflating into rows. One "active" and one normal. On click it would just return the different layout for the row clicked and have a marker to indicate which row was the currently selected one. First ran into issues I didn't expect with the inflated views being recycled as a listview is scrolled up & down. Fine, ok, so I made an extension of BaseAdapter so I could do my own thing with getView(). Well I managed to get it to correctly allow recycling of views (and not reusing the "active" one where it wasn't suppose to be) however I see no way to make it refresh / reload the alternate layout except when scrolling said row off screen and then back on. Seems there's no way to force getView() to actually happen unless a row leaves the screen and comes back.
So it's a two headed question. One is there a way to make a single row swap out inflated views while it's being displayed? And two maybe my method of doing this is a backwards way to accomplish what I want and is there a better way?
Thank you for your time!
public View getView(int position, View convertView, ViewGroup parent) {
View v;
Boolean activeExists = false;
if(convertView!=null && convertView.getTag()==(String) "active"){
activeExists=true; }
if (((position==activeFlag && activeExists==true) || (position!=activeFlag && activeExists==false)) && convertView!=null) {
v = convertView;
} else if(position==activeFlag && activeExists==false){
v = inflater.inflate(rowlayoutActive, parent, false);
v.setTag((String) "active");
} else if (position!=activeFlag && activeExists==true) {
v = inflater.inflate(rowlayout, parent, false);
} else {
v = inflater.inflate(rowlayout, parent, false);
}
bindView(position, v);
return v;
}
(Outside of this getView I have (int) activeFlag to remember which one is the current "selected" and I have my own version of bindView which doesn't really differ that much from normal. The boolean is a quick mark for already inflated views to keep the wrong one from going to the wrong row when recycled.)
Great question, and part of the answer might be that you consider the MVC model. Strictly speaking, you should modify the underlying data to cause a change in the UI which suggests adding perhaps a boolean to your data "isEditing" or similar, set it with the click then calling notifyDataSetChanged. In getView, you would test that boolean to use the appropriate layout.

Categories

Resources