问题
I have list with section, but this ListView is very slow.
I need any holder, but i don't know how I can make it.
When I had one type of view it was simple, but here I have problem.
I create holder, but when ListView is showing, I see:
"titel","title","title","item","item"
"titel","title","title","item"
"titel","title","title","item","item","item"
This is my code:
public class EntryAdapter extends ArrayAdapter<Item> {
private ArrayList<Item> items;
private LayoutInflater vi;
Context context;
private String nazwa;
public EntryAdapter(Context context,ArrayList<Item> items, String nazwa) {
super(context,0, items);
this.items = items;
this.context = context;
this.nazwa = nazwa;
vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
And my get View:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final Item i = items.get(position);
if (i != null) {
if(i.isSection()){
SectionItem si = (SectionItem)i;
convertView = vi.inflate(R.layout.list_item_section, null);
convertView.setOnClickListener(null);
convertView.setOnLongClickListener(null);
convertView.setLongClickable(false);
final TextView sectionView = (TextView) convertView.findViewById(R.id.list_item_section_text);
}else{
Obiekt ei = (Obiekt)i;
convertView = vi.inflate(R.layout.row_list, null);
final TextView title = (TextView)convertView.findViewById(R.id.row_tytul);
final TextView odleglosc = (TextView)convertView.findViewById(R.id.row_odleglosc);
final ImageView obrazek = (ImageView)convertView.findViewById(R.id.row_ikona_mala);
final LinearLayout pole = (LinearLayout)convertView.findViewById(R.id.LinearLayout1);
}
}
return convertView;
}
回答1:
I have list with section, but this ListView is very slow.
You are always inflating a new view in your getView() method. Inflating a view, typically takes a long time.
You want to re-use previous views, by checking if the 'convertView' is null or not. This will increase the performance. NOTE, you also have to implement getItemViewType()
and getViewTypeCount()
since you have two different views:
public class MyAdapter extends ArrayAdapter<Item> {
private List<Item> items;
private int TYPE_SECTION = 0;
private int TYPE_OBIEKT = 1;
private static LayoutInflater vi;
public MyAdapter(Context context, List<Item> _items) {
super(context, 0);
vi = (LayoutInflater) context.getSystemService(Service.LAYOUT_INFLATER_SERVICE);
items = _items;
}
@Override
public int getCount() {
return items.size();
}
/**
* @see android.widget.BaseAdapter#getViewTypeCount()
* Determines how many different views you have
*/
@Override
public int getViewTypeCount() {
return 2; // We have two different kinds of views
}
/**
* @see android.widget.BaseAdapter#getItemViewType(int)
*/
@Override
public int getItemViewType(int position) {
Item item = items.get(position);
if (item.isSection())
return TYPE_SECTION;
return TYPE_OBIEKT;
}
/**
* @see android.widget.ArrayAdapter#getView(int, android.view.View, android.view.ViewGroup)
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the item
final Item item = items.get(position);
if (getItemViewType(position) == TYPE_SECTION) {
// Return a SectionView object
return getSectionView(position, convertView, parent, (SectionItem) item);
}
// Return an Obiekt object
return getObiektView(position, convertView, parent, (Obiekt) item);
}
/**
* SectionView specific
*
* @param position
* @param convertView
* @param parent
* @param item
* @return
*/
public View getSectionView(int position, View convertView, ViewGroup parent, SectionItem item) {
SectionHolder holder;
if(convertView == null){
holder = new SectionHolder();
// Inflate a new View
convertView = vi.inflate(R.layout.list_item_section, null);
holder.sectionView = (TextView) convertView.findViewById(R.id.list_item_section_text);
// Set the ObiektHolder as the tag, to retrieve it for re-using
convertView.setTag(holder);
} else {
holder = (SectionHolder) convertView.getTag();
}
// Holder is never null here
holder.sectionView.setText(item.getSectionTitle());
return convertView;
}
public View getObiektView(int position, View convertView, ViewGroup parent, Obiekt item) {
ObiektHolder holder;
if(convertView == null){
holder = new ObiektHolder();
// Inflate a new View
convertView = vi.inflate(R.layout.row_list, null);
holder.title = (TextView)convertView.findViewById(R.id.row_tytul);
holder.odleglosc = (TextView)convertView.findViewById(R.id.row_odleglosc);
holder.obrazek = (ImageView)convertView.findViewById(R.id.row_ikona_mala);
holder.pole = (LinearLayout)convertView.findViewById(R.id.LinearLayout1);
// Set the ObiektHolder as the tag, to retrieve it for re-using
convertView.setTag(holder);
} else {
holder = (ObiektHolder) convertView.getTag();
}
// Holder is never null here
holder.title.setText(item.getObiektTitle());
return convertView;
}
private static class SectionHolder {
TextView sectionView;
}
private static class ObiektHolder {
TextView title;
TextView odleglosc;
ImageView obrazek;
LinearLayout pole;
}
}
NOTE: Tested and working now!
回答2:
http://www.youtube.com/watch?v=wDBM6wVEO70. Talks about listview peformance with view holder.
http://developer.android.com/training/improving-layouts/smooth-scrolling.html. Have a look at the documentation in the link under the heading Hold View Objects in a View Holder
Stright from the documentation :
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.
Example of viewholder.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list, null);
convertView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.t1=(TextView) convertView.findViewById(R.id.textView1);
holder.t2 = (TextView) convertView.findViewById(R.id.textView2);
holder.t3 = (TextView) convertView.findViewById(R.id.textView3);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
holder = (ViewHolder) convertView.getTag();
}
holder.t1.setText("set text")
holder.t2.setText("set text2");
holder.t3.setText("set text3");
return convertView;
}
}
class ViewHolder
{
TextView t1,t2,t3;
}
回答3:
First of all you have to check if convertView
is already inflated. If it's already inflated you can recycle it and you don't have to inflate it again. That's where you gain performance.
Example:
public View getView(int position, View convertView, ViewGroup parent) {
View itemView = null;
// not inflated
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.list_item_section, null);
}
// already inflated
else {
itemView = convertView;
}
// get your textview's etc.
return itemView;
}
来源:https://stackoverflow.com/questions/15497847/android-secionlist-and-holder