1

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;
}
Unmerciful
  • 1,325
  • 4
  • 21
  • 38

3 Answers3

2

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!

Entreco
  • 12,738
  • 8
  • 75
  • 95
  • I have error here: java.lang.ClassCastException: EntryAdapter$SectionViewHolder cannot EntryAdapter$ItemViewHolder com.edytor.ruciane.lista.EntryAdapter.getView(EntryAdapter.java:90) – Unmerciful Mar 20 '13 at 22:48
  • Also have a look at this post: http://stackoverflow.com/questions/4777272/android-listview-with-different-layout-for-each-row – Entreco Mar 21 '13 at 18:51
  • I modiefied the answer. I tested it, and confirm that it works. You need to also define the number of different views you have, see the modified code example. More questions? Don't hesitate to ask me. Good luck – Entreco Mar 21 '13 at 19:26
0

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;
}
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
0

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;
}
faceman
  • 1,318
  • 11
  • 20