How can I create convertView manually in following method. I read that convertView can be created manually or inflated from xml file.
public View getView(int position, View convertView, ViewGroup parent)
I am using xml file for layout.
Use View.inflate(context, resource, root);
#Override
public View getView(int position, View convertView, ViewGroup parent){
final View contentView = convertView != null ? convertView : View.inflate(context, resource, null);
}
where resource is your xml layout resource id like R.layout.list_item.
Something like that.
You can use this code inside the override getView method while extending the ArrayAdapter Class
if(convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
}
R.layout.list_item is the resource to create the view based on.
the parameter "false" is false to weather to attach to the root.
Related
Model One :
private Context mContext;
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate("layout name",parent, false);
}
Model Two:
private Context mContext;
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate("layout name", null);
}
Difference between the two snippets:
convertView = inflater.inflate("layout name" , null);
and
convertView = inflater.inflate("layout name", parent, false);
inflate with 2 prams:
inflate(int resource, ViewGroup root)
inflate with 3 prams:
inflate(int resource, ViewGroup root, boolean attachToRoot)
resource: int: ID for an XML layout resource to load (e.g., R.layout.main_page)
root: ViewGroup: Optional view to be the parent of the generated hierarchy (if attachToRoot is true), or else simply an object that provides a set of LayoutParams values for root of the returned hierarchy (if attachToRoot is false.)
attachToRoot: boolean: Whether the inflated hierarchy should be attached to the root parameter? If false, root is only used to create the correct subclass of LayoutParams for the root view in the XML.
See Android Docs.
The difference is that you can specify a parent element for the inflated layout and can control whether or not the inflated layout should be attached to the parent. You can find the documentation of LayoutInflaters here.
Btw. You can use a more readable syntax like this one:
final View viewToAdd = LayoutInflater.from(this).inflate(layoutId, null);
I defined a Adapter which extends BaseAdapter when I use ListView to display something.I overrided View getView (int position, View convertView, ViewGroup parent) method to reuse View component, in the method, I also wrote if(convertView == null) {System.out.println("test");} block. There are 50 rows data in ListView and the screen only can display about 20 rows data. when I ran the application, LogCat printed less than 50 rows of "test" though I slided the screen to make sure all data are loaded.But why ? I think it should print 50 rows data. Here is the key code:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = inflater.inflate(resource, null);
System.out.println(++count + "convertView == null:" + convertView);
}
}
someone help me please, I am a newbie.... thanks
Android does not inflate a View for every item in your adapter. It reuses inflated views previously used for other items.
The pattern for binding views in a adapter is something like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if(convertView == null) {
view = inflater.inflate(resource, null);
} else {
view = convertView;
}
// bind data to view here
return view;
}
In fact you normally would use a ViewHolder class. But first fix your basic adapter before reading about that.
Because convertView will be null only if there isn't a previously returned view that can be recycled (i.e. it's no longer on screen).
The views you return from an adapter's getView() can be recycled in later calls to getView(). The framework passes such recyclable views in via the convertView arg.
So your convertView == null branch only gets run enough times to fill the listview screen once and after that, when scrolling, these old views get recycled.
You missing return view.
ListView recycles view. How ListView's recycling mechanism works
Use a ViewHolder pattern
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(resource, null);
holder = new ViewHolder();
holder.tv = (TextView)convertView.findViewById(R.id.textView1);
//initialize views
convertView.setTag(holder);
} else {
holder =(ViewHolder) convertView.getTag();
}
// update your view here
holder.tv.setText("hi");
return convertView;
}
static class ViewHolder {
// YourViews Declaration
TextView tv; // an example
}
http://developer.android.com/design/media/lists_main.png
As you can see above, I would like to create the 3-line list.
I have looked everywhere but I can't seem to find any documentation on how to do it.
How do I write my adapter for this kind of ListView?
Do I have to extend ListActivity, include a ListView in my .xml layout, or both?
Can somebody provide further insight into it? I'll be very grateful...
You create an XML-Layout for your list-item (row) with three TextViews in a vertical LinearLayout. Then you need to subclass the ArrayAdapter to fill the TextViews. In the getView you fill the lines.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.listitem, null);
}
TextView text1 = (TextView) convertView.findViewById(R.id.textfield1);
if (text1 != null) {
text1.setText(contentArray.get(position).valueForField1);
}
// same for the other fields
return v;
}
I'm new to android programming and doing the first steps with Adapters (for a ListView).
Overriding the Adapter.getView I often see things like this:
public View getView(int position, View convertView, ViewGroup parent) {
View itemView = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.table_row, null);
} else {
itemView = convertView;
}
// play with itemView
return itemView;
}
My question is what speaks against this:
public View getView(int position, View convertView, ViewGroup parent) {
View itemView = super(position, convertView, parent);
// play with itemView
return itemView;
}
This seems to work for me but I'm sure there's a big point I'm missing :D
Thanks for reading and sorry for my bad english ...
You can use
View itemView = super(position, convertView, parent);
if only you are deriving from "ready to use" adapters (not BaseAdapter), like SimpleAdapter, or ArrayAdapter, as they already have their implementation for the getView().
Have a look at them: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.4_r2.1/android/widget/ArrayAdapter.java#361 for the ArrayAdapter, and
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.4_r2.1/android/widget/SimpleAdapter.java#113 for SimpleAdapter.
If you derive from BaseAdapter, you will have to manualy implement the whole method, as you've described in the first example, because it does not have it out of the box: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.4_r2.1/android/widget/BaseAdapter.java#BaseAdapter
The getView(..)-method of the Adapter can be multiple ways. The only question is, which one is the most efficient?
An interesting article to read and make you understand the ListView more detailed: http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
If you mean that this piece of code:
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.table_row, null);
} else {
itemView = convertView;
}
seems unnecessary for you: this piece of code allows Android to create a relatively small number of cells (equals to the number of cells that are visible on your screen +-), and then "recycle" these cells - use them over and over again while the user scrolls the list, instead of creating a cell for each object in your array.
This will help you with:
Saving memory - because you don't create view for each element in your array
Saving CPU usage - creating a view object out of xml file ("inflating") is relatively expensive task and doing so for each item in your array might choke your UI thread
I have made a ListView with an ArrayAdapter. It works. But I had to put the resource id for the item layout twice: in the adapter definition and in the getView, in the case when the View parameter is null.
// --------------------------------------------here is the FIRST use
lvShows.setAdapter(new ArrayAdapter<TvShow>(this, R.layout.show_row, allKnownShows) {
#Override
public View getView(int position, final View rowView, ViewGroup parent) {
LinearLayout showView;
if (rowView == null) {
// --------------------------------- here is the SECOND use
showView = (LinearLayout) inflater.inflate(R.layout.show_row, parent, false);
}
else {
showView = (LinearLayout) rowView;
}
((TextView) showView.getChildAt(0)).setText(time));
((TextView) showView.getChildAt(1)).setText(name);
return showView;
}
});
Such style is disgustful, of course. Could you kindly advise, what am I understanding wrong and how can I use the resource only once?
If creating a new ArrayAdapter I am setting the layout id, it should know it and use somehow. How could I reach it? Or better I would expect the Adapter to create item views automatically. Again - how can I use it?
What ArrayAdapter does with that resource we feed to it when creating a new one? All its constructors take the item resource and we manage this resource and inflate it "by hand". It is not the effective way.
You can override ArrayAdapter constructor and call super :
public ArrayAdapter<T>(Context context, TheDataType data) {
super(context, R.layout.show_row, data);
}
And store the id in a ArrayAdapter member variable. It avoid the adapter "user" to know what is the view needed for the adapter.
Or you can use a BaseAdapter.
I had looked into the source code of the ArrayAdapter, and it already does all this stuff about view creation:
// citation from public class ArrayAdapter<T>
private View createViewFromResource(int position, View convertView, ViewGroup parent,
int resource) {
View view;
TextView text;
if (convertView == null) {
view = mInflater.inflate(resource, parent, false);
} else {
view = convertView;
}
So, we should simply use it:
lvShows.setAdapter(new ArrayAdapter<TvShow>(this,
R.layout.show_row,
R.id.nameField,
allKnownShows){
public View getView(int position, final View convertView, ViewGroup parent) {
LinearLayout showView = (LinearLayout) super.getView(position, convertView, parent);
setAnythingForItem(showView);
return showView;
}
Attention: we have changed the constructor!
ArrayAdapter allows to use no-TextView item layout. But if it is not TextView itself, it should have one and the id of this very inner TextView field should be given to the constructor as the third parameter. ArrayAdapter needs it to be set, to write there Strings if the array connected to it has String elements.
It wants a TextView always, even if it doesn't need it really, if the array consists of Objects, not Strings. Otherway it checks the item layout for being a TextView and if it is not, throws an error.