• 15
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

Here is my ArrayAdapter. I would like to make this more efficient by following the ViewHolder pattern:

http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/List14.html

but am not sure how to accomplish this.

UPDATE: ViewHolder Pattern

private class QuoteAdapter extends ArrayAdapter<Quote> {

    private ArrayList<Quote> items;
    // used to keep selected position in ListView
    private int selectedPos = -1; // init value for not-selected

    public QuoteAdapter(Context context, int textViewResourceId, ArrayList<Quote> items) {
        super(context, textViewResourceId, items);
        this.items = items;
    }

    public void setSelectedPosition(int pos) {
        selectedPos = pos;
        // inform the view of this change
        notifyDataSetChanged();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        ViewHolder holder; // to reference the child views for later actions

        if (v == null) {
            LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.mainrow, null);

            // cache view fields into the holder
            holder = new ViewHolder();
            holder.nameText = (TextView) v.findViewById(R.id.nameText);
            holder.priceText = (TextView) v.findViewById(R.id.priceText);
            holder.changeText = (TextView) v.findViewById(R.id.changeText);

            // associate the holder with the view for later lookup
            v.setTag(holder);
        }
        else {
            // view already exists, get the holder instance from the view
            holder = (ViewHolder)v.getTag();
        }

        // change the row color based on selected state
        if (selectedPos == position) {
            v.setBackgroundResource(R.drawable.stocks_selected_gradient);
            holder.nameText.setTextColor(Color.WHITE);
            holder.priceText.setTextColor(Color.WHITE);
            holder.changeText.setTextColor(Color.WHITE);
        } else {
            v.setBackgroundResource(R.drawable.stocks_gradient);
            holder.nameText.setTextAppearance(getApplicationContext(), R.style.BlueText);
            holder.priceText.setTextAppearance(getApplicationContext(), R.style.BlueText);
            holder.changeText.setTextAppearance(getApplicationContext(), R.style.BlueText);
        }

        Quote q = items.get(position);
        if (q != null) {
            if (holder.nameText != null) {
                holder.nameText.setText(q.getSymbol());
            }
            if (holder.priceText != null) {
                holder.priceText.setText(q.getLastTradePriceOnly());
            }
            if (holder.changeText != null) {
                try {
                    float floatedChange = Float.valueOf(q.getChange());
                    if (floatedChange < 0) {
                        if (selectedPos != position)
                            holder.changeText.setTextAppearance(getApplicationContext(), R.style.RedText); // red
                    } else {
                        if (selectedPos != position)
                            holder.changeText.setTextAppearance(getApplicationContext(), R.style.GreenText); // green
                    }
                } catch (NumberFormatException e) {
                    System.out.println("not a number");
                } catch (NullPointerException e) {
                    System.out.println("null number");
                }
                holder.changeText.setText(q.getChange() + " (" + q.getPercentChange() + ")");
            }
        }
        return v;
    }
}

The ViewHolder is basically a static class instance that you associate with a view when it's created, caching the child views you're looking up at runtime. If the view already exists, retrieve the holder instance and use its fields instead of calling findViewById.

In your case:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    ViewHolder holder; // to reference the child views for later actions

    if (v == null) {
        LayoutInflater vi = 
            (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.mainrow, null);
        // cache view fields into the holder
        holder = new ViewHolder();
        holder.nameText = (TextView) v.findViewById(R.id.nameText);
        holder.priceText = (TextView) v.findViewById(R.id.priceText);
        holder.changeText = (TextView) v.findViewById(R.id.changeText);
        // associate the holder with the view for later lookup
        v.setTag(holder);
    }
    else {
        // view already exists, get the holder instance from the view
        holder = (ViewHolder) v.getTag();
    }
    // no local variables with findViewById here

    // use holder.nameText where you were 
    // using the local variable nameText before

    return v;
}

// somewhere else in your class definition
static class ViewHolder {
    TextView nameText;
    TextView priceText;
    TextView changeText;
}

caveat: I didn't try to compile this, so take with a grain of salt.

  • 51
Reply Report
      • 2
    • This sort of has to do with a question I asked earlier about recycling views. Do you know of any performance analysis done on the overhead of creating views?
    • @Falmarri Not specifically, no. This particular pattern is to avoid the inefficiency of findViewById rather than View creation. It would be simple to make a test case to do your own analysis of View reuse vs. creation, however. I suspect that parsing the XML layout alone would be enough cause to warrant reuse. If the View is very simple and does programmatic layout, I have no firsthand knowledge of the overhead involved in creation.
      • 2
    • great example code. I have implemented the view holder pattern. Check out v.setBackgroundResource() am I doing that correctly in relation to the View Holder pattern?
      • 2
    • @Sheehan Alam Setting the background resource and using the ViewHolder pattern aren't related. Your original code seems to be setting the background based on selection status, however. For this, you generally want to use a selector resource.
    • @codelark Why we using inner static class here for ViewHolder? Cause I know we can use here normal private inner class. Anybody knows what improvement gives us using of static inner class?

I just faced a similar problem here, but a little bit more complex, consider a very similar sample.

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    ViewHolder holder;

    if (v == null) {
        LayoutInflater vi = 
            (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.mainrow, null);
        holder = new ViewHolder();
        holder.nameText = (TextView) v.findViewById(R.id.nameText);
        holder.priceText = (TextView) v.findViewById(R.id.priceText);
        holder.myCheckbox = (Checkbox) v.findViewById(R.id.changeText);
        v.setTag(holder);
    }
    else {
        holder = (ViewHolder) v.getTag();
        /*ATTENTION - this line below was added, because i started to face some problems with view reuse of other rows, when user changed the state, the behavior of other row was triggered*/
        holder.myCheckbox.setOnCheckedChangeListener(null);
    }
    /*without the new line above, the line below trigger the old event and some strange behavior happens.*/
    holder.myCheckbox.setChecked(myList.get(position).isChecked());
    holder.myCheckbox.setOnCheckedChangeListener(()->{
       //some behavior
    });



    return v;
}

// somewhere else in your class definition
static class ViewHolder {
    TextView nameText;
    TextView priceText;
    Checkbox myCheckbox;
}

So, remember, when you use the ViewHolder Pattern, it's good to cleanup the component listeners before change the state of them.

  • 0
Reply Report