Android: Не знаете, почему мой список разобрался?

Я реализовал ListView, который работал правильно, пока я не добавил более 5 элементов и 2 заголовка. Я не совсем уверен, почему некоторые элементы не появляются, а другие появляются несколько раз. Любая помощь в исправлении этого будет высоко оценена. Код указан ниже.

Toolbox.java

public class Toolbox extends Fragment {
    private ListView lstView;
    private View rootView;
    List<Tools> tools;

    public static Toolbox newInstance(Context context) {
        Toolbox fragment = new Toolbox();
        return fragment;
    }

    public Toolbox() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        ((MainActivity) getActivity()).setActionBarTitle("Technical Toolbox");
        rootView = inflater.inflate(R.layout.fragment_toolbox, container, false);
        lstView =(ListView) rootView.findViewById(R.id.list);
        final FragmentActivity c = getActivity();
        //final RecyclerView recyclerView = (RecyclerView) recView.findViewById(R.id.reView);


        setToolBoxData();
        setToolBoxAdapter();
        return rootView;
    }

    private void setToolBoxAdapter() {
        ListArrayAdapter adapter = new ListArrayAdapter(getActivity(),tools);
        lstView.setAdapter(adapter);
    }

    private void setToolBoxData(){
        tools=new ArrayList<>();
        tools.add(new Header("Languages"));
        tools.add(new ListItem("Android",R.drawable.ic_android));
        tools.add(new ListItem("XML", R.drawable.ic_xml));
        tools.add(new ListItem("Java",R.drawable.ic_java));
        tools.add(new ListItem("JavaScript", R.drawable.ic_javascript));
        tools.add(new ListItem("C++", R.drawable.ic_cpp));
        tools.add(new ListItem("Visual Basic", R.drawable.ic_vb));
        tools.add(new ListItem("HTML", R.drawable.ic_html));
        tools.add(new ListItem("CSS", R.drawable.ic_css));
        tools.add(new Header("Source Control"));
        tools.add(new ListItem("Git", R.drawable.ic_git));
        tools.add(new ListItem("GitHub", R.drawable.ic_github_cat));
        tools.add(new ListItem("SourceTree", R.drawable.ic_sourcetree));
        tools.add(new ListItem("BitBucket", R.drawable.ic_bitbucket));
        tools.add(new Header("DataBase"));
        tools.add(new ListItem("Parse", R.drawable.ic_parse));
        tools.add(new ListItem("MS Access", R.drawable.ic_access));
        tools.add(new ListItem("SQL", R.drawable.ic_sql));
        tools.add(new Header("Design & IDE Tools"));
        tools.add(new ListItem("Android Studio", R.drawable.ic_androidstudio));
        tools.add(new ListItem("Visual Studio", R.drawable.ic_visual_studio));
        tools.add(new ListItem("Genymotion", R.drawable.ic_genymotion));
        tools.add(new ListItem("Ionic", R.drawable.ic_ionic));
        tools.add(new Header("Office Tools"));
        tools.add(new ListItem("MS Project", R.drawable.ic_project));
        tools.add(new ListItem("MS Visio", R.drawable.ic_visio));
        tools.add(new ListItem("MS Excel", R.drawable.ic_excel));
        tools.add(new ListItem("MS Word", R.drawable.ic_word));
    }
}

ListArrayAdapter.java

public class ListArrayAdapter extends ArrayAdapter<Tools> {
    private LayoutInflater mInflater;

    public enum RowType{ LIST_ITEM, HEADER_ITEM }

    public ListArrayAdapter(Context context, List<Tools> tools){
        super(context, 0, tools);
        mInflater = LayoutInflater.from(context);
    }

    @Override
    public int getViewTypeCount(){return RowType.values().length;}

    @Override
    public int getItemViewType(int pos){return getItem(pos).getViewType();}

    private static final int TYPE_ITEM = 0;
    private static final int TYPE_SEPARATOR = 1;

    public View getView(int position, View convertView, ViewGroup parent)  {
        ViewHolder holder = null;
        int rowType = getItemViewType(position);
        View View;
        if (convertView == null) {
            holder = new ViewHolder();
            switch (rowType) {
                case TYPE_ITEM:
                    convertView = mInflater.inflate(R.layout.listview_item, null);
                    holder.View=getItem(position).getView(mInflater, convertView);
                    break;
                case TYPE_SEPARATOR:
                    convertView = mInflater.inflate(R.layout.list_title, null);
                    holder.View=getItem(position).getView(mInflater, convertView);
                    break;
            }
            convertView.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) convertView.getTag();
        }
        return convertView;
    }

    public static class ViewHolder {
        public  View View;
    }
}

Tools.java

public interface Tools {
    public int getViewType();
    public View getView(LayoutInflater inflater, View convertView);
}

ListItem.java

public class ListItem implements Tools {
    private final String str1;
    private final int pic1;

    public ListItem(String text1, int pic1) {
        this.str1 = text1;
        this.pic1 = pic1;
    }

    @Override
    public int getViewType() {
        return ListArrayAdapter.RowType.LIST_ITEM.ordinal();
    }

    @Override
    public View getView(LayoutInflater inflater, View convertView) {
        View view;
        if (convertView == null) {
            view = (View) inflater.inflate(R.layout.listview_item, null);
            // Do some initialization
        } else {
            view = convertView;
        }

        TextView text1 = (TextView) view.findViewById(R.id.listText);
        ImageView picture1 = (ImageView) view.findViewById(R.id.listIcon);
        text1.setText(str1);
        picture1.setImageResource(pic1);

        return view;
    }
}

Header.java

public class Header implements Tools {
    private final String         name;

    public Header(String name) {
        this.name = name;
    }

    @Override
    public int getViewType() {
        return ListArrayAdapter.RowType.HEADER_ITEM.ordinal();
    }

    @Override
    public View getView(LayoutInflater inflater, View convertView) {
        View view;
        if (convertView == null) {
            view = (View) inflater.inflate(R.layout.header, null);
            // Do some initialization
        } else {
            view = convertView;
        }

        TextView text = (TextView) view.findViewById(R.id.separator);
        text.setText(name);

        return view;
    }
}

Ответ 1

Вы только заполняете виджеты строк в случае if (convertView == null). Если convertView не null, вы просто возвращаете его без изменений, то есть он будет иметь данные из предшествующего position, а не position, который запрашивается.

IOW, вам нужно вызвать методы типа setText() и setImageResource() в каждом getView() вызове, чтобы заполнить виджеты строк данными для запрошенного position.

Ответ 2

Вместо использования позиций вы должны использовать некоторую форму id для уникальности.

Также, когда представления переработаны, вам необходимо обновить их новыми данными.

if (convertView == null) {
        holder = new ViewHolder();
        switch (rowType) {
            case TYPE_ITEM:
                convertView = mInflater.inflate(R.layout.listview_item, null);
                holder.View=getItem(position).getView(mInflater, convertView);
                break;
            case TYPE_SEPARATOR:
                convertView = mInflater.inflate(R.layout.list_title, null);
                holder.View=getItem(position).getView(mInflater, convertView);
                break;
        }
        convertView.setTag(holder);
    }
    else
    {
        holder = (ViewHolder) convertView.getTag();
    //here update the holder in else case also.
    }

    return convertView;

Ответ 3

Краткое описание:

На самом деле, сегодня я воспользовался этой же ошибкой. Как описано выше, я также выполнил идентичную реализацию на 90-95%. Однако я видел и принятый ответ этого потока Q & A. Но я не мог согласиться с тобой! Поэтому я искал и искал, почему моя простая реализация ArrayAdapter не работала должным образом. В первый раз он загружает Okay. Но вскоре после того, как я прокручу его один раз? Все типы строк сбиваются с толку!

Обобщенный ответ:
Прочтите Android Developer Doc для получения дополнительной информации, вы можете найти подсказку напрямую. Чтобы реализовать несколько типов строк Views для ListView, мы должны по существу реализовать методы getItemViewType() и getViewTypeCount(). И документация getItemViewType() дает нам примечание следующим образом:

Примечание. Целые числа должны находиться в диапазоне от 0 до getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPE также может быть возвращен.

Итак, в вашем getItemViewType() вы должны вернуть значения для типа просмотра, начиная с 0, до последнего типа (количество типов - 1). Например, допустим, у вас есть только два типа просмотров? Поэтому в зависимости от объекта данных для представления вы можете вернуть только 0 или 1 в метод getItemViewType().

Если вы не поняли или не смогли решить проблему и нуждаетесь в дополнительной информации, пожалуйста, прочтите ее ниже:

Подробное объяснение:

В соответствии с Документацией разработчика Android или API Doc, это упомянул, что для реализации нескольких типов ListView, мы должны реализовать следующие методы:

public int getItemViewType (int position)
public int getViewTypeCount ()

И из двух вышеупомянутых методов getItemViewType имеет важное значение в нашей case (где у нас есть несколько типов просмотра). Это правда? Итак, что?

Что там, где меня и @8BitYoda пошло не так. OP неправильно, он определил Enum, где он не дает типы как диапазон integers в диапазоне от 0 до (getViewTypeCount() - 1).

И что я сделал, я определил типы следующим образом:

private static final int TYPE_ITEM = 1;
private static final int TYPE_ITEM = 2;

И сначала я не реализовал, getViewTypeCount(), поэтому я реализовал его следующим образом:

public int getViewTypeCount() {
      return 2;
}

Затем, вскоре после запуска приложения и попытке загрузить это представление с помощью ListView, он разбился, давая мне следующее исключение:

java.lang.ArrayIndexOutOfBoundsException: length = 2; Индекс = 2                                                                              в android.widget.AbsListView $RecycleBin.addScrapView(AbsListView.java:6643)                                                                              в android.widget.ListView.measureHeightOfChildren(ListView.java:1292)                                                                              в android.widget.ListView.onMeasure(ListView.java:1188):
:
:
на com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Скажи что?: O

Он косвенно говорит, что он связан с целым числом, возвращающимся из метода getViewTypeCount(), когда я возвращаюсь 2. И я возвращаю 2, потому что у меня есть только два типа. Поэтому я вернулся в Android-документацию, ища окончательную помощь. И это действительно помогло мне и разрешило мой вопрос, прочитав документ, который касается методов, которые я реализовал.

Для быстрой привязки взгляните на изображение ниже: введите описание изображения здесь

С маленьким шрифтом он дал ПРИМЕЧАНИЕ для нас.


Что говорит примечание метода getItemViewType (int position)?

Примечание. Целые числа должны находиться в диапазоне от 0 до getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPE также может быть возвращен.

Итак, сразу после этого я понял, что мне нужно повторно назначить type integers, который я отправляю, начиная с 0, независимо от количества типов, которые у меня есть, например, индекса нулевого массива. Таким образом, я снова скорректировал эти две строки, и это сработало как прелесть после этого!

private static final int TYPE_ITEM = 0;
private static final int TYPE_ITEM = 1;

Извините, я знаю, что мой ответ прошел немного дольше, чем я ожидал, почти как мини-учебник. Но мне все равно, что я провел около часа +, чтобы написать это, потому что я потратил бы около 5 часов, чтобы выяснить эту глупую ошибку. Кто думает, что типы должны назначаться начиная с 0, например, с индексом массива на основе 0?

Итак, я надеюсь, что мой ответ может быть полезен кому-то, чтобы решить эту ошибку.

Ура!!!