There is a BaseAdapter based BaseAdapter :

 public class ContactsListAdapter extends BaseAdapter{ private LayoutInflater inflater; private ArrayList<ContactsListItems> mContactsList = new ArrayList<>(); ContactsListAdapter(Context context, ArrayList<ContactsListItems> users){ mContactsList = users; inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { return mContactsList.size(); } @Override public Object getItem(int i) { return mContactsList.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View convertView, ViewGroup viewGroup) { View view = convertView; ViewHolder holder; ContactsListItems user = getUser(i); if (view == null){ holder = new ViewHolder(); if (user.getUIN() == -9){ view = inflater.inflate(R.layout.contacts_list_header, viewGroup, false); //((TextView)view.findViewById(R.id.twGroupName_header)).setText(user.getGroupName()); holder.twGroupName_header = (TextView)view.findViewById(R.id.twGroupName_header); holder.twGroupName_header.setText(user.getGroupName()); view.setTag(R.id.group_id_contacts_listview, -1); view.setTag(R.id.parent_group_id_contacts_lisview, user.getParentId()); }else { if (!user.ismIsGroup()) { view = inflater.inflate(R.layout.item_people_in_contacts, viewGroup, false); // ((TextView) view.findViewById(R.id.twContactName)).setText(user.getDisplayName()); // ((TextView) view.findViewById(R.id.twUIN)).setText("UIN:" + user.getUIN().toString()); holder.twContactName = (TextView)view.findViewById(R.id.twContactName); holder.twContactName.setText(user.getDisplayName()); holder.twUIN = (TextView)view.findViewById(R.id.twUIN); holder.twUIN.setText("UIN:" + user.getUIN().toString()); view.setTag(R.id.group_id_contacts_listview, user.getGroupId()); } else { view = inflater.inflate(R.layout.item_group_in_contacts, viewGroup, false); //((TextView) view.findViewById(R.id.twGroupName_contacts)).setText((user.getGroupName())); holder.twGroupName_contacts = (TextView)view.findViewById(R.id.twGroupName_contacts); holder.twGroupName_contacts.setText(user.getGroupName()); view.setTag(R.id.group_id_contacts_listview, user.getGroupId()); } } view.setTag(holder); } else { holder = (ViewHolder)view.getTag(); } return view; } private ContactsListItems getUser(int position) { return ((ContactsListItems) getItem(position)); } private static class ViewHolder{ TextView twContactName; TextView twUIN; TextView twGroupName_contacts; TextView twGroupName_header; } } 

And the fragment in which ListView is filled with data:

 public class Contacts extends Fragment { public ContactsListAdapter adapter; ArrayList<ContactsListItems> items = new ArrayList<>(); String CONTACTS_LIST = "contacts_list"; @Override public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment_contacts, container, false); SharedPreferences spref = MainPage.contextOfApplication.getSharedPreferences(Consts.APP_PREFERENCES, MainPage.MODE_PRIVATE); final String sData = spref.getString(CONTACTS_LIST, ""); ContactsListItems Item; try { JSONArray contactsListJson = new JSONArray(sData); for (int i=0; i<contactsListJson.length(); i++){ JSONObject user = contactsListJson.getJSONObject(i); if (user.getBoolean("IsGroup") && user.getInt("ParentID") == 0) { Item = new ContactsListItems(user.getInt("UIN"), user.getInt("Sex"), user.getInt("ParentID"), user.getInt("ID"), user.getString("DisplayName"), user.getString("GroupName"), user.getBoolean("TeamLead"), user.getBoolean("IsGroup"), user.getInt("GroupID")); items.add(Item); } } }catch (JSONException e){ } adapter = new ContactsListAdapter(getActivity(), items); final ListView listView = (ListView)view.findViewById(R.id.lwContacts); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { Integer GroupId = (Integer) view.getTag(R.id.group_id_contacts_listview); Integer parentGroupId = (Integer) view.getTag(R.id.parent_group_id_contacts_lisview); ContactsListItems ItemsOnClick; ArrayList<ContactsListItems> itemsOnClick = new ArrayList<>(); //------------------------------Обработка нажатия на группу------------------------------------- if (GroupId > 0) { try { JSONArray contactsListJson = new JSONArray(sData); for (int j = 0; j < contactsListJson.length(); j++) { JSONObject user = contactsListJson.getJSONObject(j); if (user.getInt("GroupID") == GroupId){ ContactsListItems headerItem = new ContactsListItems(-9,0,user.getInt("ParentID"),0,"", user.getString("GroupName"), false, false, user.getInt("GroupID")); itemsOnClick.add(headerItem); } if (user.getInt("ParentID") == GroupId) { ItemsOnClick = new ContactsListItems(user.getInt("UIN"), user.getInt("Sex"), user.getInt("ParentID"), user.getInt("ID"), user.getString("DisplayName"), user.getString("GroupName"), user.getBoolean("TeamLead"), user.getBoolean("IsGroup"), user.getInt("GroupID")); itemsOnClick.add(ItemsOnClick); } } } catch (JSONException e) { e.printStackTrace(); } ContactsListAdapter onClickAdapter = new ContactsListAdapter(getActivity(), itemsOnClick); listView.setAdapter(onClickAdapter); //------------------------------Обработка нажатия на группу------------------------------------- } else //------------------------------Обработка нажатия на контакт------------------------------------- if (GroupId == 0){ Toast t = Toast.makeText(getActivity(), "Contact", Toast.LENGTH_SHORT); t.show(); //------------------------------Обработка нажатия на контакт------------------------------------- } else //------------------------------Обработка нажатия на header-------------------------------------- if (GroupId == -1){ ArrayList<ContactsListItems> itemsOnBackClick = new ArrayList<>(); try { JSONArray backJson = new JSONArray(sData); ContactsListItems ItemsOnBackClick; for (int k=0; k<backJson.length(); k++){ JSONObject backUser = backJson.getJSONObject(k); if ((backUser.getInt("GroupID") == parentGroupId) && parentGroupId != 0){ ContactsListItems headerItem = new ContactsListItems(-9,0,backUser.getInt("ParentID"),0,"", backUser.getString("GroupName"), false, false, backUser.getInt("GroupID")); itemsOnBackClick.add(headerItem); } if (backUser.getInt("ParentID") == parentGroupId) { ItemsOnBackClick = new ContactsListItems(backUser.getInt("UIN"), backUser.getInt("Sex"), backUser.getInt("ParentID"), backUser.getInt("ID"), backUser.getString("DisplayName"), backUser.getString("GroupName"), backUser.getBoolean("TeamLead"), backUser.getBoolean("IsGroup"), backUser.getInt("GroupID")); itemsOnBackClick.add(ItemsOnBackClick); } ContactsListAdapter onBackClickAdapter = new ContactsListAdapter(getActivity(), itemsOnBackClick); listView.setAdapter(onBackClickAdapter); } }catch (JSONException e){ e.printStackTrace(); } } //------------------------------Обработка нажатия на header-------------------------------------- } }); return view; } } 

I am trying to implement a multi-level list. With a small number of elements, everything works well, but as soon as there are more elements than can fit on the phone’s screen, scrolling through the ListView causes the elements to shuffle. The functionality that is embedded in them is preserved, but there is no order.

Maybe someone has an idea why?

Changed the getView () method as follows:

  public View getView(int i, View convertView, ViewGroup viewGroup) { View view = convertView; ViewHolder holder; ContactsListItems user = getUser(i); if (view == null){ holder = new ViewHolder(); if (user.getUIN() == -9){ view = inflater.inflate(R.layout.contacts_list_header, viewGroup, false); holder.twGroupName_header = (TextView)view.findViewById(R.id.twGroupName_header); view.setTag(R.id.group_id_contacts_listview, -1); view.setTag(R.id.parent_group_id_contacts_lisview, user.getParentId()); }else { if (!user.ismIsGroup()) { view = inflater.inflate(R.layout.item_people_in_contacts, viewGroup, false); holder.twContactName = (TextView)view.findViewById(R.id.twContactName); holder.twUIN = (TextView)view.findViewById(R.id.twUIN); view.setTag(R.id.group_id_contacts_listview, user.getGroupId()); } else { view = inflater.inflate(R.layout.item_group_in_contacts, viewGroup, false); holder.twGroupName_contacts = (TextView)view.findViewById(R.id.twGroupName_contacts); view.setTag(R.id.group_id_contacts_listview, user.getGroupId()); } } view.setTag(holder); } else { holder = (ViewHolder)view.getTag(); } if (user.getUIN() == -9){ holder.twGroupName_header.setText(user.getGroupName()); }else { if (!user.ismIsGroup()) { holder.twContactName.setText(user.getDisplayName()); holder.twUIN.setText("UIN:" + user.getUIN().toString()); } else { holder.twGroupName_contacts.setText(user.getGroupName()); } } return view; } 

But now when scrolling, when I reach the end of the list, an error flies:

 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference 
  • In the adapter in the getView(...) method if view != null you do not link any data to the view element. - post_zeew
  • @post_zeew, do not quite understand what I have to bind - Heorhii Lysenko
  • Bind == fill in your data. For the sake of experiment in getView() crash if (view == null){ along with its alternative branch and see what happens. - tse
  • one
    @HeorhiiLysenko, you use the ViewHolder pattern - that is, reuse the already created View . In case you need to create a new View , you create it and fill it with data. In case the old View comes to getView(...) , which needs to be updated (that is, when view != null ), you do not update it, that is, do not fill it with some new (other) data. - post_zeew
  • how to use ViewHolder so that it works later. - pavlofff

1 answer 1

Although I’ll probably give up the idea of ​​using ListView in favor of RecyclerView , I did find a solution. Thanks @post_zeew for advice and information.

Adapter ListView Code:

 public class ContactsListAdapter extends BaseAdapter{ private LayoutInflater inflater; private ArrayList<ContactsListItems> mContactsList = new ArrayList<>(); ContactsListAdapter(Context context, ArrayList<ContactsListItems> users){ mContactsList = users; inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getViewTypeCount() { return 3; } @Override public int getItemViewType(int position) { Integer flag = -1; ContactsListItems user = getUser(position); if (user.getUIN() == -9){ flag = 0; }else { if (!user.ismIsGroup()) { flag = 1; } else { flag = 2; } } return flag; } @Override public int getCount() { return mContactsList.size(); } @Override public Object getItem(int i) { return mContactsList.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View convertView, ViewGroup viewGroup) { View view = convertView; ContactsListItems user = getUser(i); Integer type = getItemViewType(i); switch (type){ case 0:{ ViewHeaderHolder headerHolder; if (view == null){ view = inflater.inflate(R.layout.contacts_list_header, viewGroup, false); headerHolder = new ViewHeaderHolder(); headerHolder.twGroupName_header = (TextView)view.findViewById(R.id.twGroupName_header); view.setTag(R.id.group_id_contacts_listview, -1); view.setTag(R.id.parent_group_id_contacts_lisview, user.getParentId()); view.setTag(R.id.holder_id0, headerHolder); }else{ headerHolder = (ViewHeaderHolder)view.getTag(R.id.holder_id0); } if (headerHolder.twGroupName_header != null) { headerHolder.twGroupName_header.setText(user.getGroupName()); } return view; } case 1:{ ViewContactHolder contactHolder; if (view == null){ view = inflater.inflate(R.layout.item_people_in_contacts, viewGroup, false); contactHolder = new ViewContactHolder(); contactHolder.twContactName = (TextView)view.findViewById(R.id.twContactName); contactHolder.twUIN = (TextView)view.findViewById(R.id.twUIN); view.setTag(R.id.group_id_contacts_listview, user.getGroupId()); view.setTag(R.id.holder_id1, contactHolder); }else{ contactHolder = (ViewContactHolder)view.getTag(R.id.holder_id1); } if (contactHolder.twContactName != null) { contactHolder.twContactName.setText(user.getDisplayName()); contactHolder.twUIN.setText("UIN:" + user.getUIN().toString()); } return view; } case 2:{ ViewContactNameHolder contactNameHolder; if (view == null){ view = inflater.inflate(R.layout.item_group_in_contacts, viewGroup, false); contactNameHolder = new ViewContactNameHolder(); contactNameHolder.twGroupName_contacts = (TextView)view.findViewById(R.id.twGroupName_contacts); view.setTag(R.id.group_id_contacts_listview, user.getGroupId()); view.setTag(R.id.holder_id2, contactNameHolder); }else{ contactNameHolder = (ViewContactNameHolder)view.getTag(R.id.holder_id2); } if (contactNameHolder.twGroupName_contacts != null) { contactNameHolder.twGroupName_contacts.setText(user.getGroupName()); } return view; } } return view; } private ContactsListItems getUser(int position) { return ((ContactsListItems) getItem(position)); } private static class ViewContactNameHolder{ TextView twGroupName_contacts; } private static class ViewContactHolder{ TextView twContactName; TextView twUIN; } private static class ViewHeaderHolder{ TextView twGroupName_header; } } 

The main changes were redefinition of the getItemViewType() and getViewTypeCount() methods. In the first one I brought out the logic of data sorting, in the second I indicated the number of different layout patterns. And while I did not override getViewTypeCount() , nothing worked.