ArrayAdapter 视图在滚动列表后复制

ArrayAdapter views duplicating after scrolling list

我创建了一个自定义 ArrayAdapter,在 ArrayAdapter 内部有一个通过迭代添加视图的 LinearLayout。现在,在显示需要在 ListView 上显示的数据之后,一切都会很好,直到我向下或向上滚动列表,当一行经过回收并​​将新视图绑定到显示在回收行上时,我得到了重复项,但是这个重复项有在视图上不显示任何数据(文本)。这是滚动前的视图 ListView

https://postimg.org/image/z36eqhacd/

这里是滚动后的 ListView

https://postimg.org/image/dzv28kj9t/

我尝试了多种方法,但似乎无法正常工作。

public class SurveyAdapter extends ArrayAdapter<SurveyModel> {

public SurveyAdapter(Context context, ArrayList<SurveyModel> objects) {
    super(context, R.layout.survey_card, objects);
}

@NonNull
@Override
public View getView(int position, View convertView, @Nullable ViewGroup parent) {
    //Get the data item for this position
    SurveyModel surveyModel = getItem(position);

    //Construct the ViewHolder
    ViewHolder viewHolder = new ViewHolder();

    //Check if an existing view is being reused, otherwise inflate the view
    if (convertView == null) {
        //If there's no view to re-use, inflate a new view for a row
        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.survey_card, parent, false);
        viewHolder.mContainer = (LinearLayout) convertView.findViewById(R.id.choice_container);
        viewHolder.question = (TextView) convertView.findViewById(R.id.question);
        //Cache the viewHolder object inside the new view
        convertView.setTag(viewHolder);
    } else {
        //View is being recycled, retrieve the viewHolder object from tag
        viewHolder = (ViewHolder) convertView.getTag();
    }

    assert surveyModel != null;

    //Populate the data from the data object
    String choices = surveyModel.getChoice();

    //Scan each string separately
    //Strings are separated with a comma ','
    Scanner scanner = new Scanner(choices).useDelimiter(",\s*");

    //Create an array list to store each string separately
    ArrayList<String> choiceList = new ArrayList<>();

    //Get all strings from scanner separately
    while (scanner.hasNext()) {
        String choice = scanner.next(); //Get each string from scanner
        choiceList.add(choice); //Store the string in an ArrayList(choiceList)
    }

    //Convert choiceList(ArrayList) to a StringArray(choiceArray)
    String[] choiceArray = choiceList.toArray(new String[choiceList.size()]);

    int choiceNum; //Will store number of choices to be displayed
    if (choices.contains("Other,true") || choices.contains("Other,false")) {
        //Set number or choices to the length(number of items) of the choiceList(ArrayList)
        //Minus 1 to avoid showing "true" as an option
        choiceNum = choiceArray.length - 1;
    } else {
        //Set number or choices to the length(number of items) of the array
        choiceNum = choiceArray.length;
    }

    //Get number of choices from choiceNum
    final int numOfChoices = choiceNum;

    //Populate each choice string from choiceArray
    for (int i = 0; i < numOfChoices; i++) {
        //Create a new CheckBox for each choice
        AppCompatCheckBox checkBox = new AppCompatCheckBox(getContext());
        checkBox.setLayoutParams(new LinearLayoutCompat.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

        //Add the CheckBox to its survey_view_list view(mContainer)
        viewHolder.mContainer.addView(checkBox);

        if (viewHolder.mContainer.getChildAt(i) instanceof AppCompatCheckBox) {
            //Set each data item in the choiceArray on its own CheckBox according to position
            ((AppCompatCheckBox) viewHolder.mContainer.getChildAt(i)).setText(choiceArray[i]);

            final ViewHolder finalViewHolder = viewHolder; //Get viewHolder for inner class access
            final int checkBoxPosition = i; //Set position of the checked CheckBox

            ((AppCompatCheckBox) viewHolder.mContainer.getChildAt(i)).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
                    if (checked) {
                        for (int i = 0; i < numOfChoices; i++) {
                            //Disable all CheckBoxes when a CheckBox is checked
                            finalViewHolder.mContainer.getChildAt(i).setEnabled(false);
                            //Re-enable the checked CheckBox only
                            finalViewHolder.mContainer.getChildAt(checkBoxPosition).setEnabled(true);
                        }
                    } else {
                        for (int i = 0; i < numOfChoices; i++) {
                            //Enable all CheckBoxes when the checked CheckBox is unchecked
                            finalViewHolder.mContainer.getChildAt(i).setEnabled(true);
                        }
                    }
                }
            });
        }
    }

    //Populate the data from the data object via the viewHolder object into the view
    viewHolder.question.setText(surveyModel.getQuestion());

    //Return the completed view to render on screen
    return convertView;
}

//View lookup cache
private static class ViewHolder {
    LinearLayout mContainer;
    TextView question;
}`

这是对象模型

public class SurveyModel {

private String question, choice;

public String getQuestion() {
    return question;
}

public void setQuestion(String question) {
    this.question = question;
}

public String getChoice() {
    return choice;
}

public void setChoice(String choice) {
    this.choice = choice;
}
}

这是 Activity 中的方法 我将 ArrayAdapter 附加到 ListView

//Method to populate and display data populated from the database
private void populateAndDisplayData() {

//Construct ArrayList
    ArrayList<SurveyModel> surveyModelArrayList = new ArrayList<>();

    //Construct adapter
    SurveyAdapter adapter = new SurveyAdapter(CreateFromScratch.this, surveyModelArrayList);

    //Attach the adapter to the ListView
    binding.list.setAdapter(adapter);

    //Create a ListView
    ListView listView = new ListView(CreateFromScratch.this);

    //Get all the data from the database
    Cursor allDataCursor = tempSurveyDatabase.fetchAllData();

    //StringArray to hold the strings from the database
    String[] from = new String[]{CustomSurveyDatabase.QUESTION, CustomSurveyDatabase.CHOICES};

    //Views to display the string data from StringArray(from)
    int[] to = new int[]{R.id.question, R.id.choices};

    //Construct a SimpleCursorAdapter
    SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(CreateFromScratch.this, R.layout.survey_card, allDataCursor, from, to);

    // /Attach the adapter to the ListView
    listView.setAdapter(simpleCursorAdapter);

    //Construct StringBuilder
    StringBuilder jsonBuilder = new StringBuilder();

    //Strings to hold the item's data from the database
    String question = null;
    String choices = null;

    //Proceed with collecting each item's data if the SimpleCursorAdapter is not empty
    if (simpleCursorAdapter.getCount() > 0) {
        //Get every item's id from the database
        for (int i = 0; i < simpleCursorAdapter.getCount(); i++) {

            //Get each item's database id
            long itemId = listView.getAdapter().getItemId(i);

            //Get each item from the database
            try {
                //Construct cursor to fetch an item's data from the database
                Cursor cursor = tempSurveyDatabase.fetchItem(itemId);
                question = tempSurveyDatabase.questionHolder;
                choices = tempSurveyDatabase.choiceHolder;
            } catch (SQLException e) {
                Log.v(TAG, e.getMessage());
            }

            if (i == 0) {
                jsonBuilder.append("{\"survey\": [").append("{\"question\":\"").append(question).append("\",");
                jsonBuilder.append("\"choices\":\"").append(choices).append("\"},");
            } else {
                jsonBuilder.append("{\"question\":\"").append(question).append("\",");
                jsonBuilder.append("\"choices\":\"").append(choices).append("\"},");
            }
        }

        //Remove the last comma from the StringBuilder
        jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
        //Close JSON file scopes
        jsonBuilder.append("]}");

        //Save temporary survey file on the SDCARD
        try {
            //Delete existing temporary survey
            if (TEMP_SURVEY.exists()) {
                //noinspection ResultOfMethodCallIgnored
                TEMP_SURVEY.delete();
            }
            FileWriter fileWriter = new FileWriter(TEMP_SURVEY);
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
            bufferedWriter.write(String.valueOf(jsonBuilder));
            bufferedWriter.close();
        } catch (IOException e) {
            Log.v(TAG, "Temp Survey JSON file failed to write.\nReason: " + e.getMessage());
        }

        //Check if the temporary survey file exists
        if (TEMP_SURVEY.exists()) {
            //Read the temporary survey file if it exists
            new ReadFile(ReadFile.data, ReadFile.output, TEMP_SURVEY);
            //Parse JSON string from StringBuilder
            try {
                JSONObject jsonObjectMain = new JSONObject(ReadFile.output);
                JSONArray jsonArray = jsonObjectMain.getJSONArray(SurveyJSONKeys.ARRAY_KEY);
                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    SurveyModel surveyModel = new SurveyModel();
                    surveyModel.setQuestion(jsonObject.getString(SurveyJSONKeys.QUESTION_KEY));
                    surveyModel.setChoice(jsonObject.getString(SurveyJSONKeys.CHOICES_KEY));
                    surveyModelArrayList.add(surveyModel);
                }
            } catch (JSONException e) {
                Log.v(TAG, "Unable to parse JSON file.\nReason: " + e.getMessage());
            }
            //Notify the adapter for changes in order to refresh views
            adapter.notifyDataSetChanged();
        }
    }
}`

由于您的项目视图每次都会被回收,因此您的答案容器只是附加了更多答案。您有 2 个选择:

  1. 在填充答案之前移除容器中的所有子视图
  2. 不要使用 getViewTypeCount()getItemViewType(int) 强制回收。