我只有一种布局夸大了。将新项目添加到列表视图后,我按如下方式捕获了此异常,当我尝试向上滚动时会发生这种情况。如果getViewTypeCount()返回1,则我会有一个很大的problem

D/countOfType﹕ getViewTypeCount() = 8
D/countOfType﹕ getViewTypeCount() = 7

java.lang.ArrayIndexOutOfBoundsException: length=9; index=9
        at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:6563)


这是我的适配器的代码

 @Override
public View getView(final int position, final View convertView, ViewGroup parent) {
    View row = convertView;
    final Tracker tracker = trackerList.get(position);
    final Thread thread = tracker.getThread();
    ViewHolder holder;
    long days,hours,minutes,seconds;
    long eDays,eHours,eMins,eSecs;

    if(row == null){
        row = inflater.inflate(R.layout.list_item,parent,false);
        holder = new ViewHolder(row);
        row.setTag(holder);
    }else {
        holder = (ViewHolder) row.getTag();
    }

    //изнальначальный вид
    final ViewHolder finalHolder = holder;
    finalHolder.start.setVisibility(View.VISIBLE);
    finalHolder.stop.setVisibility(View.GONE);
    finalHolder.name.setText(tracker.getName());
    Log.d("TrackAdapter","getView() = "+position);
    if(tracker.getElapsedTime()!=0 && tracker.getLimitTime()==0){//если прошедшее время !=0 и таймер без лимита
        days = tracker.getElapsedTime()/86400000;
        hours = (tracker.getElapsedTime()/3600000)%24;
        minutes = (tracker.getElapsedTime()/60000)%60;
        seconds = (tracker.getElapsedTime()/1000)%60;
        if(days!=0)
            finalHolder.days.setText(Util.concat(days <= 9 ? 0 : "", days));
        if(hours!=0)
            finalHolder.hours.setText(Util.concat(hours <=9 ?0:"",hours));
        if(minutes!=0)
            finalHolder.minutes.setText(Util.concat(minutes<=9?0:"",minutes));
        if(seconds!=0)
            finalHolder.seconds.setText(Util.concat(seconds<=9?0:"",seconds));
    }else{
        if(tracker.getIsFinished()){//если таск закончен, дошел до лимита
            hours = (tracker.getLimitTime()/3600000)%24;
            minutes = (tracker.getLimitTime()/60000)%60;
            seconds = (tracker.getLimitTime()/1000)%60;
            finalHolder.start.setVisibility(View.GONE);
            finalHolder.textFinish.setVisibility(View.VISIBLE);
            finalHolder.stop.setVisibility(View.GONE);
            if(seconds!=60)
                finalHolder.seconds.setText(Util.concat(seconds<=9?0:"",seconds));
            if(minutes!=60)
                finalHolder.minutes.setText(Util.concat(minutes<=9?0:"",minutes));
            if(hours!=24)
                finalHolder.hours.setText(Util.concat(hours <= 9 ? 0 : "", hours));

        }else{
            if(tracker.getLimitTime()!=0){//если установлен лимит, но еще не дошел до конца
                days = tracker.getLimitTime()/86400000;
                hours = (tracker.getLimitTime()/3600000)%24;
                minutes = (tracker.getLimitTime()/60000)%60;
                finalHolder.textLimit.setVisibility(View.VISIBLE);
                finalHolder.limHours.setVisibility(View.VISIBLE);
                finalHolder.limDay.setVisibility(View.VISIBLE);
                finalHolder.limMin.setVisibility(View.VISIBLE);
                finalHolder.limDay.setText(Util.concat(days <= 9 ? 0 : "", days, ":"));
                finalHolder.limHours.setText(Util.concat(hours <= 9 ? 0 : "", hours, ":"));
                finalHolder.limMin.setText(Util.concat(minutes<=9?0:"",minutes));

                eDays = (tracker.getElapsedTime() / 86400000);
                eHours = (tracker.getElapsedTime()/3600000)%24;
                eMins = (tracker.getElapsedTime()/60000)%60;
                eSecs = (tracker.getElapsedTime()/1000)%60;

                if(eSecs!=0)
                    finalHolder.seconds.setText(Util.concat(eSecs<=9?0:"",eSecs));
                if(eMins!=0)
                    finalHolder.minutes.setText(Util.concat(minutes<=9?0:"",eMins));
                if(eHours!=0)
                    finalHolder.hours.setText(Util.concat(hours<= 9 ? 0 : "", eHours));
                if(eSecs!=0)
                    finalHolder.days.setText(Util.concat(days<= 9 ? 0 : "", eDays));


            }else {
                finalHolder.textLimit.setVisibility(View.GONE);
                finalHolder.limHours.setVisibility(View.GONE);
                finalHolder.limDay.setVisibility(View.GONE);
                finalHolder.limMin.setVisibility(View.GONE);
            }
        }
    }
    if(tracker.getIsStart() && !tracker.getIsFinished()) {//если был стартован
        finalHolder.start.setVisibility(View.GONE);
        finalHolder.stop.setVisibility(View.VISIBLE);
    }
    tracker.setHolder(finalHolder);
    View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btStart:
                    tracker.setStartTime(System.currentTimeMillis());
                    tracker.setIsStart(true);
                    tracker.setHolder(finalHolder);
                    finalHolder.start.setVisibility(View.GONE);
                    finalHolder.stop.setVisibility(View.VISIBLE);
                    if(tracker.getUpdateTime()==0)
                        thread.start();
                    else
                        tracker.getThread().start();

                    break;
                case R.id.btStop:
                    tracker.setLastPause(tracker.getUpdateTime());
                    finalHolder.stop.setVisibility(View.GONE);
                    finalHolder.start.setVisibility(View.VISIBLE);
                    tracker.setIsStart(false);
                    break;

            }
        }
    };
    finalHolder.start.setOnClickListener(onClickListener);
    finalHolder.stop.setOnClickListener(onClickListener);
    return row;
}

@Override
public int getViewTypeCount() {
    Log.d("countOfType","getViewTypeCount() = "+getCount());
   if(getCount()==0)
      return super.getViewTypeCount();
    else
      return getCount();
    //return 1;
}

@Override
public int getItemViewType(int position) {
    return position;
}


static class ViewHolder{
  @InjectView(R.id.tvName) TextView name;
  @InjectView(R.id.tvDays) TextView  days;
  @InjectView(R.id.tvHours) TextView  hours;
  @InjectView(R.id.tvMinutes) TextView minutes;
  @InjectView(R.id.tvSeconds) TextView  seconds;
  @InjectView(R.id.btStart) ButtonFloatSmall start;
  @InjectView(R.id.btStop) ButtonFloatSmall stop;
  @InjectView(R.id.txtFinish) TextView  textFinish;
  @InjectView(R.id.txtLimit) TextView textLimit;
  @InjectView(R.id.limDay) TextView limDay;
  @InjectView(R.id.limHours) TextView limHours;
  @InjectView(R.id.limMin) TextView limMin;

    public ViewHolder(View view){
        ButterKnife.inject(this,view);
    }
}

最佳答案

TL; DR作为一般规则,对于if中的每个getView(...),请确保有一个处理负数的else,否则您将在视图中看到旧数据。



您似乎误解了getItemViewType(int position)getViewTypeCount()的角色。 Here很好地说明了为什么以及如何使用它们。

在您的情况下,由于只有一种布局,因此不必实现这两种方法。如果您在视图中看到回收的数据,则getView(...)方法中存在一些错误。使用数据填充视图时,请确保处理所有情况。

例如,假设您有一个项目列表,并且如果位置为偶数,则要显示红色背景,如果位置为奇数,则要显示蓝色。让我们还假设默认情况下您的视图具有红色背景。您可以这样实现getView(...)

@Override
public View getView(final int position, final View convertView, ViewGroup parent) {
    if(convertView == null) {
        //Inflate your view here
    }
    if(position % 2 != 1) {
        //Only need to change background if we're odd, since it's red by default
        convertView.setBackgroundColor(Color.BLUE);
    }
}


乍一看,这似乎是一个不错的实现。但是,当您添加视图回收时,您会发现某些偶数视图最终可能带有蓝色背景。这样做的原因是因为您没有显式设置偶数视图的背景,因此它们将保持其在上一行中使用的颜色。更好的实现是:

@Override
public View getView(final int position, final View convertView, ViewGroup parent) {
    if(convertView == null) {
        //Inflate your view here
    }
    if(position % 2 != 1) {
        convertView.setBackgroundColor(Color.BLUE);
    } else {
        //Set the background no matter what so we make sure our view reflects our data
        convertView.setBackgroundColor(Color.RED);
    }
}

08-05 13:52