滚动列表后重复的ArrayAdapter视图

问题描述:

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

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

前视图ListView和这里是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; 
} 
} 

下面是从活动的方法我一个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(); 
     } 
    } 
}` 
+0

在您滚动时动态构建视图看起来像是解决方案的一个糟糕方法。你想要做什么? –

+0

我同意,我可以简单地夸大布局,而不是动态地创建视图。每当一行被回收并且它已被修复时,我想修复重复的视图。 –

由于您的项目视图被回收的每一次,你的答案的容器只是附加更多的答案。你有两个选择:

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

非常感谢。我知道在填充数据之前删除所有视图是关键,而且我之前尝试过,但是我在迭代开始时实现了“viewHolder.mContainer.removeAllViews()”语句,这是错误的,因为它保留删除了意见,所以我按照第一点建议的方式进行了操作,并将陈述放在所有数据人口陈述之前,并且在回收后不再有重复。 –

+0

很高兴帮助! :) – tompee