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?
Итак, я надеюсь, что мой ответ может быть полезен кому-то, чтобы решить эту ошибку.
Ура!!!