使用ViewHolder的ListView,TextViews更改内容

时间:2013-12-30 16:47:34

标签: android listview android-listview

我有ListView个自定义CursorAdapter。在那里我有这个:

if (Main.distance_unit.equals(Main.miValue)) {
                //[...] some code here which converts units

                holder.mi.setText(mileageResult + " " + Main.distance_unit);
            } else if (Main.distance_unit.equals(Main.km)) {
                holder.mi.append(" " + Main.distance_unit);
            }

现在的问题是,当我第一次打开ListView片段时,一切都很好,但是当再次向下滚动时,单位会消失。我认为这是由ViewHolder引起的吗?我该如何解决这个问题?

Before scrolling

After scrolling

整个代码,可能是一些愚蠢的代码行。欢迎您建议更好的方法来做这些事情:

public MyCursorAdapter(Context context, Cursor c, String[] from, int[] to) {
        //noinspection deprecation
        super(context, R.layout.activity_db_row, c, from, to);

        mCursor = c;
        ctx = context;
        mInflater = LayoutInflater.from(ctx);
    }

    @Override
    public View getView(int position, View v, ViewGroup parent) {
        super.getView(position, v, parent);
        mCursor.moveToPosition(position);
        ViewHolder holder = new ViewHolder();

        if (v == null) {
            mInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = mInflater.inflate(R.layout.activity_db_row, parent, false);
            //noinspection deprecation
            v.setBackgroundDrawable(null);

            DecimalFormatSymbols dfs = new DecimalFormatSymbols();
            dfs.setDecimalSeparator('.');
            decimalFormat.setDecimalFormatSymbols(dfs);
            decimalFormatGal.setDecimalFormatSymbols(dfs);

            holder.price = (RobotoTextView) v.findViewById(R.id.lv_tprice_unit);
            holder.price.setText(Main.money_unit);

            holder.lprice = (RobotoTextView) v.findViewById(R.id.lv_lprice_unit);
            holder.lprice.setText(Main.money_unit + "/" + Main.amount_unit);

            holder.amount_unit = (RobotoTextView) v.findViewById(R.id.lv_amount_unit);
            if (Main.amount_unit.equals(Main.galValueImp)) {
                holder.amount_unit.setText(Main.galValue);
            } else holder.amount_unit.setText(Main.amount_unit);

            bindView(v, ctx, mCursor);

            holder.am = (RobotoTextView) v.findViewById(R.id.lv_amount);
            String amount = holder.am.getText().toString();
            holder.am.setText(String.valueOf(decimalFormatGal.format(Double.parseDouble(amount))));

            holder.mi = (RobotoTextView) v.findViewById(R.id.lv_mileage);
            String mileage = holder.mi.getText().toString();

            holder.tp = (RobotoTextView) v.findViewById(R.id.lv_tprice);
            String tprice = holder.tp.getText().toString();
            holder.tp.setText(String.valueOf(decimalFormat.format(Double.parseDouble(tprice))));

            holder.lp = (RobotoTextView) v.findViewById(R.id.lv_lprice);

            holder.d = (RobotoTextView) v.findViewById(R.id.lv_date);

            holder.fuel = (RobotoTextView) v.findViewById(R.id.lv_fueltype);
            String fueltype = holder.fuel.getText().toString();

            if(fueltype.equals("null") || fueltype.length() == 0) {
                holder.fuel.setText("");

                //ToDo: Remove at some point
            }

            String amountResult;
            if (Main.amount_unit.equals(Main.galValue)) {
                BigDecimal amountTmp, toGal, resultTmp;
                double amountDouble = Double.parseDouble(amount);
                amountTmp = BigDecimal.valueOf(amountDouble);
                toGal = BigDecimal.valueOf(DbAdapter.toGal);

                resultTmp = amountTmp.multiply(toGal).setScale(2,
                        RoundingMode.HALF_UP);
                amountResult = resultTmp.toString();

                holder.am.setText(String.valueOf(decimalFormat.format(Double.parseDouble(amountResult))));

            }

            if (Main.amount_unit.equals(Main.galValueImp)) {
                BigDecimal amountTmp, toImpGal, resultTmp;
                double amountDouble = Double.parseDouble(amount);
                amountTmp = BigDecimal.valueOf(amountDouble);
                toImpGal = BigDecimal.valueOf(DbAdapter.toImpGal);

                resultTmp = amountTmp.multiply(toImpGal).setScale(2,
                        RoundingMode.HALF_UP);
                amountResult = resultTmp.toString();

                holder.am.setText(String.valueOf(decimalFormat.format(Double.parseDouble(amountResult))));

            }

            if (Main.distance_unit.equals(Main.miValue)) {
                BigDecimal mileageTmp, toMi, resultTmp;

                double mileageDouble = Double.parseDouble(mileage);
                mileageTmp = BigDecimal.valueOf(mileageDouble);
                toMi = BigDecimal.valueOf(DbAdapter.toMi);

                resultTmp = mileageTmp.multiply(toMi).setScale(2,
                        RoundingMode.HALF_UP);
                String mileageResult = resultTmp.toString();

                holder.mi.setText(mileageResult + " " + Main.distance_unit);
            } else if (Main.distance_unit.equals(Main.km)) {
                holder.mi.append(" " + Main.distance_unit);
            }



            v.setTag(holder);
        } else holder = (ViewHolder) v.getTag();
        return v;

    }

    public static class ViewHolder {
        RobotoTextView price;
        RobotoTextView lprice;
        RobotoTextView amount_unit;
        RobotoTextView am;
        RobotoTextView mi;
        RobotoTextView tp;
        RobotoTextView lp;
        RobotoTextView d;
        RobotoTextView fuel;
    }

2 个答案:

答案 0 :(得分:2)

请参阅此处的示例模式:

@Override
public View getView(int position, View v, ViewGroup parent) {
    mCursor.moveToPosition(position);

    if (v == null) {
        /* inflate your view if "v" is null */
        mInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = mInflater.inflate(R.layout.activity_db_row, parent, false);            

        /* hold the reference of your view through ViewHolder */
        ViewHolder holder = new ViewHolder();
        holder.price = (RobotoTextView) v.findViewById(R.id.lv_tprice_unit);

        ......

       /* set view tag */
       v.setTag(holder);
    }

   /* This is where you should update your view state values */
   ViewHolder holder = (ViewHolder) v.getTag();

   DecimalFormatSymbols dfs = new DecimalFormatSymbols();
   dfs.setDecimalSeparator('.');
   decimalFormat.setDecimalFormatSymbols(dfs);

   holder.price.setText(Main.money_unit); 

   ..... update view's 
  return v;

}

您的示例代码段会发生什么?在listview的第一次迭代。您的代码片段工作正常 因为视图基本上还没有被回收。在你的问题上。这是视图得到回收。 由于视图可能已经被回收,因此不会执行if(v == null)。这就是为什么你的观点 状态属性未更新。

答案 1 :(得分:0)

您每次都在创建new ViewHolder()。如果convertView为null,则需要创建新实例。如果convertView不为null,则获取持有者。在任何一种情况下,您都需要将值设置为视图。你使用的模式错了。请查看下面的示例代码,其中说明了如何正确使用视图持有者:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolderItem viewHolder;

    /*
     * The convertView argument is essentially a "ScrapView" as described is Lucas post 
     * http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
     * It will have a non-null value when ListView is asking you recycle the row layout. 
     * So, when convertView is not null, you should simply update its contents instead of inflating a new row layout.
     */
    if(convertView==null){

        // inflate the layout
        LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
        convertView = inflater.inflate(layoutResourceId, parent, false);

        // well set up the ViewHolder
        viewHolder = new ViewHolderItem();
        viewHolder.textViewItem = (TextView) convertView.findViewById(R.id.textViewItem);

        // store the holder with the view.
        convertView.setTag(viewHolder);

    }else{
        // we've just avoided calling findViewById() on resource everytime
        // just use the viewHolder
        viewHolder = (ViewHolderItem) convertView.getTag();
    }

    // object item based on the position
    ObjectItem objectItem = data[position];

    // assign values if the object is not null
    if(objectItem != null) {
        // get the TextView from the ViewHolder and then set the text (item name) and tag (item ID) values
        viewHolder.textViewItem.setText(objectItem.itemName);
        viewHolder.textViewItem.setTag(objectItem.itemId);
    }

    return convertView;

}

致谢/来源:http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html