Android 带ViewHolder的ListView,文本视图更改内容

Android 带ViewHolder的ListView,文本视图更改内容,android,listview,android-listview,Android,Listview,Android Listview,我有一个带有自定义光标或适配器的列表视图。在那里我有这样一个: if (Main.distance_unit.equals(Main.miValue)) { //[...] some code here which converts units holder.mi.setText(mileageResult + " " + Main.distance_unit); } else if (Main.dista

我有一个带有自定义
光标或适配器的
列表视图
。在那里我有这样一个:

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
片段时,一切都很好,但是当再次向下和向上滚动时,单位消失了。我认为这是由
视图持有者造成的,对吗?我怎样才能解决这个问题

整个代码,可能有几行愚蠢的代码。欢迎您提出更好的方法来完成这些事情:

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;
    }

请参见此处的示例模式:

@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)引发的。这就是你的观点的原因
状态属性未更新。

您每次都在创建一个
新的ViewHolder()
。如果
convertView
为空,则需要创建一个新实例。如果
convertView
不为空,则获取保持架。在任何一种情况下,都需要为视图设置值。你用错了图案。请查看下面解释如何正确使用视图支架的示例代码:

@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;

}

信用/来源:

可能是bcoz listview回收视图请在完成后为我们调试“MyCusorAdapter”的整个代码的方法存在问题。谢谢@Raghunandan是的,我在问题中提到了这一点。我不知道怎么解决这个问题。谢谢。现在我开始了解
ViewHolder
的工作原理。