Getview参数“convertview”在新的“position”参数上不为null

时间:2013-08-19 21:57:32

标签: android listview android-arrayadapter convertview

我正在使用ArrayAdapter获取我自己的对象类型列表(只有一种类型),并且我为用户提供了创建更多项目的选项(从而为这些项目创建更多视图)。在某些时候,getView发送了一个带有非null“convertView”的新“位置”索引。然后它显示最后一个位置的第一个视图。之后,当滚动视图时,所有内容都会混淆。我假设这意味着我以不应该的方式操纵视图,但我只是看不到。这是一些代码:

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

    // Initialize view if convertview is null
    if (convertView == null) {
        v = newView(parent, position);
    }
    // Populate from previously saved holder
    else {
        // Use previous item if not null
        v = convertView;
    }

    // Populate if the holder is null (newly inflated view) OR
    // if current view's holder's flag is true and requires populating
    if ((holder == null) || (holder.readPopulateFlag())) {
        bindView(position, v);
    }

    return v;
}

    private View newView(ViewGroup parent, int position) {
    // Getting view somehow...
    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View inflatedView = inflater.inflate(R.layout.preview_element_set, parent, false);
    PreviewItemHolder holder = new PreviewItemHolder();

    holder.set = (Set) mSets.get(position);
    holder.previewElementHolders = new ArrayList<PreviewElementHolder>();
    holder.expandArea = (View) inflatedView.findViewById(R.id.expandArea);
    holder.repetitionsLabel = (TextView) inflatedView.findViewById(R.id.previewRepetitionsInput);
    holder.endlessInput = (CheckBox) inflatedView.findViewById(R.id.previewSetEndlessInput);
    holder.nameLabel = (TextView) inflatedView.findViewById(R.id.previewSetNameLabel);
    holder.commentInput = (EditText) inflatedView.findViewById(R.id.previewSetCommentInput);
    holder.soundInput = (EditText) inflatedView.findViewById(R.id.previewSetSoundInput);
    holder.addElementButton = (Button) inflatedView.findViewById(R.id.previewSetAddElements);
    holder.expand = (View) inflatedView.findViewById(R.id.infoArea);
    holder.collapse = (View) inflatedView.findViewById(R.id.collapse);

    final int setsLength = holder.set.getElements().size();

    for (int i = 0; i < setsLength; i++) {
        AElement currElement = holder.set.getElements().get(i);

        // Creating new element holder according to the type
        if (currElement instanceof Rest) {
            holder.previewElementHolders.add(new PreviewRestHolder());
        }
        else if (currElement instanceof TimeExercise) {
            holder.previewElementHolders.add(new PreviewTimeExerciseHolder());
        }
        else if (currElement instanceof RepetitionExercise) {
            holder.previewElementHolders.add(new PreviewRepetitionExerciseHolder());
        }

        View currLayout = inflateElement(currElement, inflater, i, holder.previewElementHolders.get(i));

        // Add the child before the hairline, collapse image and the add
        // button
        // (3 last children of the expandArea view
        ((ViewGroup) holder.expandArea).addView(currLayout, ((ViewGroup) holder.expandArea).getChildCount() - CHILDREN_INDEX_AFTER_PHASES_LABEL);
    }

    inflatedView.setTag(holder);

    return inflatedView;
}

private void bindView(int position, View inflatedView) {
    final PreviewItemHolder holder = (PreviewItemHolder) inflatedView.getTag();
    holder.set.setId(position);
    holder.endlessInput.setChecked(holder.set.getEndless());
    holder.soundInput.setText(holder.set.getSound());
    holder.nameLabel.setText(holder.set.getName());
    holder.commentInput.setText(holder.set.getComment());

    // Make sure there is a name. If none, put default
    if (holder.nameLabel.getText().equals("")) {
        holder.nameLabel.setText(R.string.default_set_name);
    }

    // Set repetitions value according to the endless flag
    if (holder.set.getEndless()) {
        holder.repetitionsLabel.setText(R.string.infinity);
    }
    else {
        holder.repetitionsLabel.setText(String.valueOf(holder.set.getRepetitions()));
    }

    // Set click listeners
    holder.endlessInput.setOnCheckedChangeListener(new OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

            // Save endless flag
            holder.set.setEndless(isChecked);

            // If an endless set - Dropset
            if (isChecked) {
                holder.repetitionsLabel.setText(R.string.infinity);
            }
            else {
                // Regular set
                holder.repetitionsLabel.setText(String.valueOf(holder.set.getRepetitions()));
            }

            hideShowRepsWeights(holder);
        }

    });

    holder.repetitionsLabel.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {

            NumericDialog instance = NumericDialog.newInstance(holder, holder.set, NumericDialog.INTEGER_MODE, Consts.SET_REPETITIONS_METHOD_NAME);
            instance.show(((Activity) getContext()).getFragmentManager(), null);
        }
    });

    holder.nameLabel.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            // Setting flag to true to allow populating this view
            holder.rePopulateFlag = true;
            SetNameDialog instance = SetNameDialog.newInstance(holder.set);
            instance.show(((Activity) getContext()).getFragmentManager(), null);
        }
    });

    holder.commentInput.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                // After focus is lost, save the text into the set
                holder.set.setComment(holder.commentInput.getText().toString());
            }
        }
    });

    // TODO Change that into a dialog that allows selection of sounds
    holder.soundInput.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                // After focus is lost, save the text into the set
                holder.set.setSound(holder.soundInput.getText().toString());
            }
        }
    });

    holder.expand.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            // Change visibility - Show expandArea and its data
            holder.expandArea.setVisibility(View.VISIBLE);
            holder.expand.setVisibility(View.GONE);
            holder.collapse.setVisibility(View.VISIBLE);
        }
    });

    holder.collapse.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            // Change visibility - Hide expandArea and its data
            holder.expandArea.setVisibility(View.GONE);
            holder.collapse.setVisibility(View.GONE);
            holder.expand.setVisibility(View.VISIBLE);
        }
    });

    holder.addElementButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            AddElementDialog instance = AddElementDialog.newInstance(holder);
            instance.show(((Activity) getContext()).getFragmentManager(), null);
        }
    });

    // Populate elements
    for (PreviewElementHolder elementHolder : holder.previewElementHolders) {
        populateElement(elementHolder, holder);
    }

    // Finally hide/show if needed - Should this be put somewere else?
    hideShowRepsWeights(holder);
}

如果您认为我应该上传更多方法以使事情更清楚,请告诉我。

3 个答案:

答案 0 :(得分:15)

一位朋友向我解释了这个问题,现在似乎有效。基本上ListView只保存少量视图并一直循环使用它们。在我的情况下,我有一个Nexus 4,所以它似乎总共有7个视图,因为第8个总是那个开始造成麻烦的人。我在getView()中缺少的是检查ArrayAdapter中当前项的位置和ID之间的相关性的条件。以下是它的工作原理:

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

    // Initialize view if convertview is null
    if (convertView == null) {
        v = newView(parent, position);
    }
    // Populate from previously saved holder
    else {
        // If position and id of set do not match, this view needs to be re-created, not recycled
        if (((PreviewItemHolder) convertView.getTag()).set.getId() != position) {
            v = newView(parent, position);
        }
        else {
            // Use previous item if not null
            v = convertView;

            // Get holder
            holder = (PreviewItemHolder) v.getTag();
        }
    }

    // Populate if the holder is null (newly inflated view) OR
    // if current view's holder's flag is true and requires populating
     if ((holder == null) || (holder.readPopulateFlag())) {
    bindView(position, v);
     }

    return v;
}

答案 1 :(得分:1)

您需要致电bindView() 始终。想法或重用如下。如果convertView为null,则创建并初始化新视图。如果convertView不为空,则您可以使用此视图并转换为新视图,这意味着您使用bindView()实例调用convertView

结帐this Javadoc了解详情。

答案 2 :(得分:0)

当你有几种类型的应该回收的视图时,你必须通过实现方法告诉列表视图你有多少种类型

SELECT *
, CAST(NULL as NVARCHAR(100)) as NewColumn1
, CAST(NULL as INT) as NewColumn2

INTO B
FROM A
WHERE 1=0