Одинаковый хэш-код элементов ListView

Интерфейс, диалоги, темы, стили, меню
Ответить
ne1c
Сообщения: 3
Зарегистрирован: 16 фев 2015, 01:18

Одинаковый хэш-код элементов ListView

Сообщение ne1c » 16 фев 2015, 01:27

У меня есть ListView с кастомным элементом. В этом кастомном элементе есть кнопка для которой я прописал селектор и состояния. Для адаптера использовал BaseAdapter. Для примера установил 9 элементов списка. Вот содержимое метода getView:

Код: Выделить всё

    @Override
    public View getView(final int position, View convertView, final ViewGroup parent) {
        View view = convertView;
        ViewHolderItem viewHolderItem;
        if (view == null){
            view = mInflater.inflate(R.layout.item_news, parent, false);

            viewHolderItem = new ViewHolderItem();

            viewHolderItem.infoText = (TextView) view.findViewById(R.id.info_text_textView);
            viewHolderItem.likeButton = (FButton) view.findViewById(R.id.like_post_button);
            viewHolderItem.card = (CardView) view.findViewById(R.id.news_item_cardView);

            view.setTag(viewHolderItem);

        } else {
            viewHolderItem = (ViewHolderItem) view.getTag();
        }

        viewHolderItem.infoText.setText(items[position]);
        viewHolderItem.likeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.setSelected(!v.isSelected());
            }
        });

        viewHolderItem.card.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("MYTAG", "Position: " + position + " Hash: " + Long.toString(v.hashCode()));
            }
        });

        return view;
    }

    static class ViewHolderItem {
        TextView infoText;
        FButton likeButton;
        CardView card;
    }
Когда я нажимаю на кнопку в первом элемента, то я фиксирую её как нажатая:

Код: Выделить всё

v.setSelected(!v.isSelected());
Но пролистав вниз, когда все первые элементы ушли с экрана и заменились другими у меня каким-то чудом стала выделенная кнопка и в 6 элементе. Не много расследовав эту магию, мне удалось выяснить что хэш-код первого элемента и 6-го совпадают, соответственно хэш-код 2-го с 7-м совпадают и т.д. Как можно это исправить, чтобы при прокрутке состояние элемента оставалось неизменным и не повторялось на других?
Если заметить, то я использую паттерн ViewHolder.

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Одинаковый хэш-код элементов ListView

Сообщение Foenix » 16 фев 2015, 11:06

изменять нажато или отжато (так же как и радиобаттоны, и все что угодно другое - т.е. состояние строк листвью) нужно в getView в зависимости от ДАННЫХ, а не просто бац-бац. Там ведь идет работа с памятью и листвью использует уже созданные строки для отображения следующих - почитай о нем хотя бы теорию и все поймешь.
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

ne1c
Сообщения: 3
Зарегистрирован: 16 фев 2015, 01:18

Re: Одинаковый хэш-код элементов ListView

Сообщение ne1c » 16 фев 2015, 15:19

Хорошо. Я сохраняю значение isSelected в Map-e, но результат тот же:

Код: Выделить всё

public class NewsAdapter extends BaseAdapter{
    private String[] items = new String[]{"TEST TEXT 1","TEST TEXT 2","TEST TEXT 3","TEST TEXT 4",
            "TEST TEXT 5", "TEST TEXT 6", "TEST TEXT 7","TEST TEXT 8","TEST TEXT 9"};

    private Context mContext;
    private LayoutInflater mInflater;
    private Map<Integer, Boolean> mItemStatus;

    public NewsAdapter(Context _context){
        mContext = _context;
        mInflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        mItemStatus = new HashMap<>();
        for (int i = 0; i < 9; i++){
            mItemStatus.put(i, false);
        }
    }

    @Override
    public int getCount() {
        return items.length;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, final ViewGroup parent) {
        View view = convertView;
        ViewHolderItem viewHolderItem;
        if (view == null){
            view = mInflater.inflate(R.layout.item_news, parent, false);

            viewHolderItem = new ViewHolderItem();

            viewHolderItem.infoText = (TextView) view.findViewById(R.id.info_text_textView);
            viewHolderItem.likeButton = (FButton) view.findViewById(R.id.like_post_button);
            viewHolderItem.card = (CardView) view.findViewById(R.id.news_item_cardView);
            if (mItemStatus.get(position)){
                viewHolderItem.likeButton.setSelected(true);
            }

            view.setTag(viewHolderItem);

        } else {
            viewHolderItem = (ViewHolderItem) view.getTag();
        }

        viewHolderItem.infoText.setText(items[position]);
        viewHolderItem.likeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mItemStatus.get(position)) {
                    v.setSelected(false);
                    mItemStatus.put(position, false);
                } else {
                    v.setSelected(true);
                    mItemStatus.put(position, true);
                }
            }
        });

        viewHolderItem.card.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext, "Position: " + position + " Hash: " + Long.toString(v.hashCode()), Toast.LENGTH_SHORT).show();
                Log.d("MYTAG", "Position: " + position + " Hash: " + Long.toString(v.hashCode()));
            }
        });

        return view;
    }

    static class ViewHolderItem {
        TextView infoText;
        FButton likeButton;
        CardView card;
    }
}

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Одинаковый хэш-код элементов ListView

Сообщение Foenix » 16 фев 2015, 21:10

а где у тебя выделение пункта списка в зависимости от данных?
вот ты пишешь
viewHolderItem.infoText.setText(items[position]);
а где такое же, Только для чекбокса?
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

Аватара пользователя
mdzht
Сообщения: 124
Зарегистрирован: 11 ноя 2013, 11:33
Откуда: fock it
Контактная информация:

Re: Одинаковый хэш-код элементов ListView

Сообщение mdzht » 18 фев 2015, 07:39

ne1c писал(а):Хорошо. Я сохраняю значение isSelected в Map-e, но результат тот же:
братишка, лучше обработай likeButton, для обоих случаев
[syntax=java5]public class Like implements View.OnClickListener {
private String mId;
private ViewHolder holder;
private String owner_id;
private int lPosition;

public Like(String id, String oid, ViewHolder h, int lPosition) {
mId = id;
holder = h;
owner_id = oid;
this.lPosition = lPosition;
}

@Override
public void onClick(final View view) {

final ViewHolder v = holder;
v.like.setText("likes");
getItem(lPosition).setCanLike(0);
getItem(lPosition).setLikeCount(likeCount);
if(Constants.Extra.SDK < android.os.Build.VERSION_CODES.JELLY_BEAN) {
v.like.setBackgroundDrawable(like_full);
} else {
v.like.setBackground(like_full);
}

v.like.setOnClickListener(new Dislike(mId,owner_id, v, lPosition));
}
});
}
}[/syntax]
и для Dislike
[syntax=java5]public class Dislike implements View.OnClickListener {
private String mId;
private ViewHolder holder;
private String owner_id;
private int lPosition;

public Dislike(String id, String oid, ViewHolder h, int lPosition) {
mId = id;
holder = h;
owner_id = oid;
this.lPosition = lPosition;
}

@Override
public void onClick(final View view) {

final ViewHolder v = holder;
v.like.setText("dislikes");
getItem(lPosition).setCanLike(1);
getItem(lPosition).setLikeCount(likeCount);
if(Constants.Extra.SDK < android.os.Build.VERSION_CODES.JELLY_BEAN) {
v.like.setBackgroundDrawable(like_empty);
} else {
v.like.setBackground(like_empty);
}
v.like.setOnClickListener(new Like(mId,owner_id, v, lPosition));
}
});
}
}[/syntax]
зы: если опечатки есть, сам разберешься
«Life is too short to spend rewriting code»

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Одинаковый хэш-код элементов ListView

Сообщение KamiSempai » 18 фев 2015, 15:33

mdzht писал(а):
ne1c писал(а):Хорошо. Я сохраняю значение isSelected в Map-e, но результат тот же:
братишка, лучше обработай likeButton, для обоих случаев
[syntax=java5]public class Like implements View.OnClickListener {
private String mId;
private ViewHolder holder;
private String owner_id;
private int lPosition;

public Like(String id, String oid, ViewHolder h, int lPosition) {
mId = id;
holder = h;
owner_id = oid;
this.lPosition = lPosition;
}

@Override
public void onClick(final View view) {

final ViewHolder v = holder;
v.like.setText("likes");
getItem(lPosition).setCanLike(0);
getItem(lPosition).setLikeCount(likeCount);
if(Constants.Extra.SDK < android.os.Build.VERSION_CODES.JELLY_BEAN) {
v.like.setBackgroundDrawable(like_full);
} else {
v.like.setBackground(like_full);
}

v.like.setOnClickListener(new Dislike(mId,owner_id, v, lPosition));
}
});
}
}[/syntax]
и для Dislike
[syntax=java5]public class Dislike implements View.OnClickListener {
private String mId;
private ViewHolder holder;
private String owner_id;
private int lPosition;

public Dislike(String id, String oid, ViewHolder h, int lPosition) {
mId = id;
holder = h;
owner_id = oid;
this.lPosition = lPosition;
}

@Override
public void onClick(final View view) {

final ViewHolder v = holder;
v.like.setText("dislikes");
getItem(lPosition).setCanLike(1);
getItem(lPosition).setLikeCount(likeCount);
if(Constants.Extra.SDK < android.os.Build.VERSION_CODES.JELLY_BEAN) {
v.like.setBackgroundDrawable(like_empty);
} else {
v.like.setBackground(like_empty);
}
v.like.setOnClickListener(new Like(mId,owner_id, v, lPosition));
}
});
}
}[/syntax]
зы: если опечатки есть, сам разберешься
Дурной пример.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

ne1c
Сообщения: 3
Зарегистрирован: 16 фев 2015, 01:18

Re: Одинаковый хэш-код элементов ListView

Сообщение ne1c » 18 фев 2015, 15:37

Я сделал так:

Код: Выделить всё

public class NewsAdapter extends BaseAdapter{ 
    private String[] items = new String[]{"TEST TEXT 1","TEST TEXT 2","TEST TEXT 3","TEST TEXT 4", 
            "TEST TEXT 5", "TEST TEXT 6", "TEST TEXT 7","TEST TEXT 8","TEST TEXT 9"}; 
 
    private Context mContext; 
    private LayoutInflater mInflater; 
    private Map<Integer, Boolean> mItemStatus; 
 
    public NewsAdapter(Context _context){ 
        mContext = _context; 
        mInflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
 
        mItemStatus = new HashMap<>(); 
        for (int i = 0; i < 9; i++){ 
            mItemStatus.put(i, false); 
        } 
    } 
 
    @Override 
    public int getCount() { 
        return items.length; 
    } 
 
    @Override 
    public Object getItem(int position) { 
        return null; 
    } 
 
    @Override 
    public long getItemId(int position) { 
        return position; 
    } 
 
    @Override 
    public View getView(final int position, View convertView, final ViewGroup parent) { 
        View view = convertView; 
        ViewHolderItem viewHolderItem; 
        if (view == null){ 
            view = mInflater.inflate(R.layout.item_news, parent, false); 
 
            viewHolderItem = new ViewHolderItem(); 
 
            viewHolderItem.infoText = (TextView) view.findViewById(R.id.info_text_textView); 
            viewHolderItem.likeButton = (FButton) view.findViewById(R.id.like_post_button); 
            viewHolderItem.card = (CardView) view.findViewById(R.id.news_item_cardView); 
            if (mItemStatus.get(position)){ 
                viewHolderItem.likeButton.setSelected(true); 
            } 
 
            view.setTag(viewHolderItem); 
 
        } else { 
            viewHolderItem = (ViewHolderItem) view.getTag(); 
        } 
 
        viewHolderItem.infoText.setText(items[position]); 
        viewHolderItem.likeButton.setSelected(mItemStatus.get(position)); //Эта строка всё порешала
        viewHolderItem.likeButton.setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                if (mItemStatus.get(position)) { 
                    v.setSelected(false); 
                    mItemStatus.put(position, false); 
                } else { 
                    v.setSelected(true); 
                    mItemStatus.put(position, true); 
                } 
            } 
        }); 
 
        viewHolderItem.card.setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                Toast.makeText(mContext, "Position: " + position + " Hash: " + Long.toString(v.hashCode()), Toast.LENGTH_SHORT).show(); 
                Log.d("MYTAG", "Position: " + position + " Hash: " + Long.toString(v.hashCode())); 
            } 
        }); 
 
        return view; 
    } 
 
    static class ViewHolderItem { 
        TextView infoText; 
        FButton likeButton; 
        CardView card; 
    } 
} 
Но теперь не сохраняет состояние нажатой кнопки при смене ориентации. Я полагаю mItemStatus надо сохранять в Bundle, но как передать Bundle в адаптер?

Аватара пользователя
mdzht
Сообщения: 124
Зарегистрирован: 11 ноя 2013, 11:33
Откуда: fock it
Контактная информация:

Re: Одинаковый хэш-код элементов ListView

Сообщение mdzht » 18 фев 2015, 15:46

KamiSempai писал(а): Дурной пример.
обоснуй.
«Life is too short to spend rewriting code»

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Одинаковый хэш-код элементов ListView

Сообщение KamiSempai » 18 фев 2015, 15:58

ne1c писал(а):Я сделал так:
Вот это уже на много лучше.
Что я посоветую:
1) Проверять полученные значения из HashMap на null;
2) Добавить в адаптер метод onSaveInstanceState, где будет сохраняться HashMap.
3) Когда в активити будет вызываться onSaveInstanceState, вызывать этот же метод и у адаптера, тем самым сохраняя данные адаптера в Bundle.
4) Добавить в адаптер метод onRestoreInstanceState, где будет восстанавливаться HashMap.
5) Когда в активити будет вызываться onRestoreInstanceState, вызывать этот же метод и у адаптера.

PS: Описанный мной метод не идеален, но для новичка сойдет.
mdzht писал(а):KamiSempai писал(а):
Дурной пример.

обоснуй.
Мало того, что в примере View и Model перемешаны в одном месте, так еще при клике, каждый раз, создаются новые объекты.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
mdzht
Сообщения: 124
Зарегистрирован: 11 ноя 2013, 11:33
Откуда: fock it
Контактная информация:

Re: Одинаковый хэш-код элементов ListView

Сообщение mdzht » 18 фев 2015, 18:35

KamiSempai писал(а):Мало того, что в примере View и Model перемешаны в одном месте, так еще при клике, каждый раз, создаются новые объекты.
как сделать лучше?
«Life is too short to spend rewriting code»

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Одинаковый хэш-код элементов ListView

Сообщение KamiSempai » 18 фев 2015, 19:08

mdzht писал(а):как сделать лучше?
ne1c писал(а):Я сделал так:

Код: Выделить всё

public class NewsAdapter extends BaseAdapter{ 
    private String[] items = new String[]{"TEST TEXT 1","TEST TEXT 2","TEST TEXT 3","TEST TEXT 4", 
            "TEST TEXT 5", "TEST TEXT 6", "TEST TEXT 7","TEST TEXT 8","TEST TEXT 9"}; 
 
    private Context mContext; 
    private LayoutInflater mInflater; 
    private Map<Integer, Boolean> mItemStatus; 
 
    public NewsAdapter(Context _context){ 
        mContext = _context; 
        mInflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
 
        mItemStatus = new HashMap<>(); 
        for (int i = 0; i < 9; i++){ 
            mItemStatus.put(i, false); 
        } 
    } 
 
    @Override 
    public int getCount() { 
        return items.length; 
    } 
 
    @Override 
    public Object getItem(int position) { 
        return null; 
    } 
 
    @Override 
    public long getItemId(int position) { 
        return position; 
    } 
 
    @Override 
    public View getView(final int position, View convertView, final ViewGroup parent) { 
        View view = convertView; 
        ViewHolderItem viewHolderItem; 
        if (view == null){ 
            view = mInflater.inflate(R.layout.item_news, parent, false); 
 
            viewHolderItem = new ViewHolderItem(); 
 
            viewHolderItem.infoText = (TextView) view.findViewById(R.id.info_text_textView); 
            viewHolderItem.likeButton = (FButton) view.findViewById(R.id.like_post_button); 
            viewHolderItem.card = (CardView) view.findViewById(R.id.news_item_cardView); 
            if (mItemStatus.get(position)){ 
                viewHolderItem.likeButton.setSelected(true); 
            } 
 
            view.setTag(viewHolderItem); 
 
        } else { 
            viewHolderItem = (ViewHolderItem) view.getTag(); 
        } 
 
        viewHolderItem.infoText.setText(items[position]); 
        viewHolderItem.likeButton.setSelected(mItemStatus.get(position)); //Эта строка всё порешала
        viewHolderItem.likeButton.setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                if (mItemStatus.get(position)) { 
                    v.setSelected(false); 
                    mItemStatus.put(position, false); 
                } else { 
                    v.setSelected(true); 
                    mItemStatus.put(position, true); 
                } 
            } 
        }); 
 
        viewHolderItem.card.setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                Toast.makeText(mContext, "Position: " + position + " Hash: " + Long.toString(v.hashCode()), Toast.LENGTH_SHORT).show(); 
                Log.d("MYTAG", "Position: " + position + " Hash: " + Long.toString(v.hashCode())); 
            } 
        }); 
 
        return view; 
    } 
 
    static class ViewHolderItem { 
        TextView infoText; 
        FButton likeButton; 
        CardView card; 
    } 
} 
KamiSempai писал(а):Что я посоветую:
1) Проверять полученные значения из HashMap на null;
2) Добавить в адаптер метод onSaveInstanceState, где будет сохраняться HashMap.
3) Когда в активити будет вызываться onSaveInstanceState, вызывать этот же метод и у адаптера, тем самым сохраняя данные адаптера в Bundle.
4) Добавить в адаптер метод onRestoreInstanceState, где будет восстанавливаться HashMap.
5) Когда в активити будет вызываться onRestoreInstanceState, вызывать этот же метод и у адаптера.
:lol:

А вообще, это долго объяснять. Советую изучить паттерны MVC, MVP, MVVM. Тогда все станет ясно.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
mdzht
Сообщения: 124
Зарегистрирован: 11 ноя 2013, 11:33
Откуда: fock it
Контактная информация:

Re: Одинаковый хэш-код элементов ListView

Сообщение mdzht » 18 фев 2015, 19:12

KamiSempai писал(а):Что я посоветую:
1) Проверять полученные значения из HashMap на null;
2) Добавить в адаптер метод onSaveInstanceState, где будет сохраняться HashMap.
3) Когда в активити будет вызываться onSaveInstanceState, вызывать этот же метод и у адаптера, тем самым сохраняя данные адаптера в Bundle.
4) Добавить в адаптер метод onRestoreInstanceState, где будет восстанавливаться HashMap.
5) Когда в активити будет вызываться onRestoreInstanceState, вызывать этот же метод и у адаптера.
:lol:

А вообще, это долго объяснять. Советую изучить паттерны MVC, MVP, MVVM. Тогда все станет ясно.
я использую ArrayList<MYOBJECT> почему хэшмап? может(определенно) я что то не знаю.
«Life is too short to spend rewriting code»

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Одинаковый хэш-код элементов ListView

Сообщение KamiSempai » 19 фев 2015, 11:14

По тому, что HashMap заполняется по мере выбора элементов, а ArrayList нужно сразу создавать нужного размера.
Кстати, здесь даже лучше подойдет HashSet. Советую использовать его.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Ответить