1

Am getting the following warning in Eclipse:

"Unconditional layout inflation from view adapter: Should use View Holder pattern (use recycled view passed into this method as the second parameter) for smoother scrolling"

The code which i had used is:

class myadapter extends ArrayAdapter<String>
{
    Context context;
    int[] images;
    String[] mytitle;
    String[] mydescp;
    myadapter(Context c, String[] tittle, int[] imgs, String[] desc)
    {
        super(c, R.layout.single_row, R.id.listView1, tittle);
        this.context=c;
        this.images=imgs;
        this.mytitle= tittle;
        this.mydescp=desc;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        LayoutInflater inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View row = inflator.inflate(R.layout.single_row, parent, false);
        ImageView myImage = (ImageView) row.findViewById(R.id.imageView1);
        TextView myText = (TextView) row.findViewById(R.id.textView1);
        TextView mydesc = (TextView) row.findViewById(R.id.textView2);

        myImage.setImageResource(images[position]);
        myText.setText(mytitle[position]);
        mydesc.setText(mydescp[position]);

        return row;
    }
}

Am getting warning in the line : View row = inflator.inflate(R.layout.single_row, parent, false);

And it causes my android application to Force Close... What can i do it now?? Any Suggestions???

Vinesh Senthilvel
  • 201
  • 2
  • 3
  • 9

5 Answers5

2

You need to recycle your views.What android as a system cares about is only the items that are visible.So you have to recycle the row items which are out of focus to be re-used for the newitems. Or else imagine the amount of caching involved.

@Override
public View getView(int position, View row, ViewGroup parent) {
    // TODO Auto-generated method stub
    if(row==null){
     LayoutInflater inflator = (LayoutInflater)   context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    row = inflator.inflate(R.layout.single_row, parent, false);
  }

    ImageView myImage = (ImageView) row.findViewById(R.id.imageView1);
    TextView myText = (TextView) row.findViewById(R.id.textView1);
    TextView mydesc = (TextView) row.findViewById(R.id.textView2);

    myImage.setImageResource(images[position]);
    myText.setText(mytitle[position]);
    mydesc.setText(mydescp[position]);

    return row;
}
Droidekas
  • 3,464
  • 2
  • 26
  • 40
1

You should re-use the view instead of inflating again and again. This brings down performance.

From your code,

 View row = inflator.inflate(R.layout.single_row, parent, false);

this will inflate everytime when you scroll. To maximize the performance, use it like

//re-use
if (row == null)
{
  inflate code here
}
else
{
  you already have a view `row`, just use it. 
}

You can see, for the first time row will be null & it will inflate and store it in View row. But, from the next time, it's not going to inflate again and again instead it will use the View row. (Re-use)

"Unconditional layout inflation from view adapter: Should use View Holder pattern (use recycled view passed into this method as the second parameter) for smoother scrolling"

It's not the error it's just the warning for asking you to use ViewHolder Pattern. Let me explain you why it's important.

Without ViewHolder Pattern :

  1. The first time it was loaded, convertView is null. We’ll have to inflate our list item layout and find the TextView via findViewById().

  2. The second time it was loaded, convertView is not null, good! We don’t have to inflate it again. But we’ll use findViewById() again.

  3. The following times it was loaded, convertView is definitely not null. But findViewById() is constantly called, it will work but, it slows down the performance especially if you have lots of items and Views in your ListView.

With the ViewHolder Design Pattern :

  1. The first time it was loaded, convertView is null. We’ll have to inflate our list item layout, instantiate the ViewHolder, find the TextView via findViewById() and assign it to the ViewHolder, and set the ViewHolder as tag of convertView.

  2. The second time it was loaded, convertView is not null, good! We don’t have to inflate it again. And here’s the sweet thing, we won’t have to call findViewById() since we can now access the TextView via its ViewHolder.

  3. The following time it was loaded, convertView is definitely not null. The findViewById() is never called again, and that makes our smooth ListView scrolling.

Why to use?

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.

So, what is ViewHolder?

A ViewHolder object stores each of the component views inside the tag field of the Layout, so you can immediately access them without the need to look them up repeatedly. First, you need to create a class to hold your exact set of views.

How to use?

  1. Make a separate class as ViewHolder & declare what you use like EditText,TextView etc..

      static class ViewHolder {
      TextView text;
      TextView timestamp;
      ImageView icon;
      ProgressBar progress;
      int position;
      }
    
  2. Then populate the ViewHolder and store it inside the layout.

     public View getView(int position, View convertView, ViewGroup parent) { 
             ViewHolder holder; 
    
             if (convertView == null) { // if convertView is null
                 convertView = mInflater.inflate(R.layout.mylayout, 
                         parent, false);
                 holder = new ViewHolder(); 
                     // initialize views  
                convertView.setTag(holder);  // set tag on view
            } else { 
                holder = (ViewHolder) convertView.getTag();
                        // if not null get tag 
                        // no need to initialize
            } 
    
            //update views here  
            return convertView; 
    }
    

Source :

Making ListView Scrolling Smooth from Android documentation

Android ViewHolder Pattern example

Yuva Raj
  • 3,881
  • 1
  • 19
  • 30
0

You have to use this code

View row = convertView;

before this line,

View row = inflator.inflate(R.layout.single_row, parent, false);

Hope it works..

Hemant Shori
  • 2,463
  • 1
  • 22
  • 20
Surender Kumar
  • 1,123
  • 8
  • 15
0

Hi Vinesh Senthilvel , Don't worry Use my code below , It will definetely solve your problem,

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        LayoutInflater inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View row = inflator.inflate(R.layout.single_row, null, false);
        ImageView myImage = (ImageView) row.findViewById(R.id.imageView1);
        TextView myText = (TextView) row.findViewById(R.id.textView1);
        TextView mydesc = (TextView) row.findViewById(R.id.textView2);

        myImage.setImageResource(images[position]);
        myText.setText(mytitle[position]);
        mydesc.setText(mydescp[position]);

        return row;
    }

If still problem persists then post logcat exception stack trace ,I will help you

Gaganpreet Singh
  • 886
  • 1
  • 9
  • 20
0

There is a another approach , You just have to import android.view.LayoutInflater; and take the context of parent (ViewGroup) - parent.getContext() ,It will work

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    View v = LayoutInflater.from(parent.getContext()).inflate(
            R.layout.single_row, parent, false);
Hemant Shori
  • 2,463
  • 1
  • 22
  • 20