Проблема с отображением элементов ListView. Строки перемешиваются

Heorhii Lysenko

Имеется ListViewAdapter на основе 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;
    }
}
</contactslistitems></contactslistitems>

И фрагмент, в котором ListView заполняется данными:

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("***"),="" 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.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</contactslistitems></contactslistitems></contactslistjson.length();></contactslistitems>

Пытаюсь реализовать многоуровневый список. При небольшом количестве элементов все работает хорошо, но как только элементов становится больше, чем помещается на экране телефона, при прокрутке ListView элементы начинают перемешиваться. Функциональность, которая в них вложена сохраняется, а вот порядок нет.

Может есть у кого-то предположения, почему так?

Изменил метод getView() таким образом:

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;
    }

Но теперь при прокручивании, когда дохожу до конца списка, вылетает ошибка:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
1 ответ

Heorhii Lysenko

Хоть я и скорее всего откажусь от идеи использования ListView в пользу RecyclerView, но решение все же нашел. Спасибо @post_zeew за советы и информацию.

Код ListView адаптера:

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;
    }
}
</contactslistitems></contactslistitems>

Основными изменениями стало переопределение методов getItemViewType() и getViewTypeCount(). В первый я вынес логику сортировки данных, во втором указал количество разных layout-ов. Причем пока не переопределил getViewTypeCount(), ничего не работало.

licensed under cc by-sa 3.0 with attribution.