Форум программистов, компьютерный форум CyberForum.ru

Программирование Android

Войти
Регистрация
Восстановить пароль
 
Grafity
59 / 4 / 1
Регистрация: 31.07.2013
Сообщений: 42
#1

Непонятный баг в ListView - Программирование Android

21.08.2013, 14:18. Просмотров 694. Ответов 8
Метки нет (Все метки)

В общем, суть такова:

Имеется список контактов в ListView. Каждый пункт содержит аватарку, имя и телефон.

Адаптер ListView:

Кликните здесь для просмотра всего текста

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
class ContactAdapter extends BaseAdapter{
        
        private class ViewHolder {
            public TextView name;
            public TextView telephone;
            public ImageView image;
        }
 
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return userContacts.size();
        }
 
        @Override
        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return userContacts.get(position);
        }
 
        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return position;
        }
 
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            
            View view = convertView;
            final Contact p = getContact(position);
            
            listener = new OnTouchListener() {
                 
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    // TODO Auto-generated method stub
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            from = event.getX();
                            break;
                        case MotionEvent.ACTION_MOVE:
                            
                            Log.i("log_tag", "Движение");
                            Log.i("log_tag", "Флаг действия: " + action_flag);
                            
                            if (action_flag == false){
                                
                                ListViewAnalizeSwipe(from, event.getX(), v);
                                
                            }
                            
                            break;
                        case MotionEvent.ACTION_UP:
                            
                            Log.i("log_tag","Отпускание");
                            action_flag = false;
                            
                    }
                    return true;
                }
            };
            
            final ViewHolder holder;
            
            
            if (convertView == null) {
                
                view = getLayoutInflater().inflate(R.layout.item, parent, false);
                
                holder = new ViewHolder();
                holder.name = (TextView) view.findViewById(R.id.name_tv);
                holder.telephone = (TextView) view.findViewById(R.id.tel_tv);
                holder.image = (ImageView) view.findViewById(R.id.contact_icon);
                view.setTag(holder);
                
            }
            else{
                holder = (ViewHolder) view.getTag();
            }
            
            if (view != convertView) {
                view.setOnTouchListener(listener);
            }
            
            holder.name.setText(p.name);
            holder.telephone.setText(p.tel);
            
            Log.i("AcyncTask", "Устанавливаем аватар контакту: " + p.id + " " + p.name);
            
            BitmapAsyncLoad bmLoad = new BitmapAsyncLoad(holder.image);
            bmLoad.execute((int) p.photo_id);
            
            return view;
        }
        
        Contact getContact(int position) {
            return ((Contact) getItem(position));
          }
        
        class BitmapAsyncLoad extends AsyncTask<Integer, Void, Bitmap>{
            
            private final WeakReference<ImageView> imageViewReference;
            
            public BitmapAsyncLoad(ImageView imageView) {
                imageViewReference = new WeakReference<ImageView>(imageView);
            }
 
            @Override
            protected Bitmap doInBackground(Integer... imageDataRow) {
                // TODO Auto-generated method stub
                Cursor c = getContentResolver().query(ContactsContract.Data.CONTENT_URI, new String[] {
                        ContactsContract.CommonDataKinds.Photo.PHOTO
                    }, ContactsContract.Data._ID + "=?", new String[] {
                        Integer.toString(imageDataRow[0])
                    }, null);
                    byte[] imageBytes = null;
                    if (c != null) {
                        if (c.moveToFirst()) {
                            imageBytes = c.getBlob(0);
                        }
                        c.close();
                    }
                    if (imageBytes != null) {
                        return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); 
                    } else {
                        return null;
                    }
                    
                
                //return queryContactImage(imageDataRow[0]);
            }
            
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                
                if (isCancelled()) {
                    Log.i("onPostExecute", "Отмена");
                    bitmap = null;
                }
                if (imageViewReference != null) {
                    ImageView imageView = imageViewReference.get();
                    if (bitmap != null){ 
                        imageView.setImageBitmap(bitmap);
                        Log.i("onPostExecute", "Установка аватара");
                    }
                    else{
                        imageView.setImageDrawable(getResources().getDrawable(R.drawable.standart_contact));
                        Log.i("onPostExecute", "Аватар отсутствует");
                    }
                }
            }
            
        }
 
    }


Проблема заключается в следующем:

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

Вот лог:

Кликните здесь для просмотра всего текста


08-21 11:55:45.408: I/AcyncTask(16646): Устанавливаем аватар контакту: 87 Дамир
08-21 11:55:45.503: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:51.758: I/AcyncTask(16646): Устанавливаем аватар контакту: 275 Дамир
08-21 11:55:51.783: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.768: I/AcyncTask(16646): Устанавливаем аватар контакту: 198 Дашка
08-21 11:55:55.793: I/onPostExecute(16646): Установка аватара
08-21 11:55:55.803: I/AcyncTask(16646): Устанавливаем аватар контакту: 260 NCC
08-21 11:55:55.808: I/AcyncTask(16646): Устанавливаем аватар контакту: 738 NCC
08-21 11:55:55.808: I/AcyncTask(16646): Устанавливаем аватар контакту: 691 Андрей ВАЗ
08-21 11:55:55.808: I/AcyncTask(16646): Устанавливаем аватар контакту: 258 Андрей Мастер
08-21 11:55:55.813: I/AcyncTask(16646): Устанавливаем аватар контакту: 730 Андрей НашТольятти
08-21 11:55:55.813: I/AcyncTask(16646): Устанавливаем аватар контакту: 681 Анискин Анатолий
08-21 11:55:55.813: I/AcyncTask(16646): Устанавливаем аватар контакту: 73 Антон Литта
08-21 11:55:55.823: I/AcyncTask(16646): Устанавливаем аватар контакту: 260 NCC
08-21 11:55:55.823: I/AcyncTask(16646): Устанавливаем аватар контакту: 738 NCC
08-21 11:55:55.828: I/AcyncTask(16646): Устанавливаем аватар контакту: 691 Андрей ВАЗ
08-21 11:55:55.828: I/AcyncTask(16646): Устанавливаем аватар контакту: 258 Андрей Мастер
08-21 11:55:55.828: I/AcyncTask(16646): Устанавливаем аватар контакту: 730 Андрей НашТольятти
08-21 11:55:55.833: I/AcyncTask(16646): Устанавливаем аватар контакту: 681 Анискин Анатолий
08-21 11:55:55.833: I/AcyncTask(16646): Устанавливаем аватар контакту: 73 Антон Литта
08-21 11:55:55.843: I/AcyncTask(16646): Устанавливаем аватар контакту: 260 NCC
08-21 11:55:55.848: I/AcyncTask(16646): Устанавливаем аватар контакту: 738 NCC
08-21 11:55:55.848: I/AcyncTask(16646): Устанавливаем аватар контакту: 691 Андрей ВАЗ
08-21 11:55:55.853: I/AcyncTask(16646): Устанавливаем аватар контакту: 258 Андрей Мастер
08-21 11:55:55.853: I/AcyncTask(16646): Устанавливаем аватар контакту: 730 Андрей НашТольятти
08-21 11:55:55.853: I/AcyncTask(16646): Устанавливаем аватар контакту: 681 Анискин Анатолий
08-21 11:55:55.863: I/AcyncTask(16646): Устанавливаем аватар контакту: 260 NCC
08-21 11:55:55.863: I/AcyncTask(16646): Устанавливаем аватар контакту: 738 NCC
08-21 11:55:55.863: I/AcyncTask(16646): Устанавливаем аватар контакту: 691 Андрей ВАЗ
08-21 11:55:55.868: I/AcyncTask(16646): Устанавливаем аватар контакту: 258 Андрей Мастер
08-21 11:55:55.868: I/AcyncTask(16646): Устанавливаем аватар контакту: 730 Андрей НашТольятти
08-21 11:55:55.873: I/AcyncTask(16646): Устанавливаем аватар контакту: 681 Анискин Анатолий
08-21 11:55:55.908: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.913: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.913: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.913: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.913: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.913: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.918: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.918: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.978: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.988: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:55.998: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.003: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.008: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.013: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.023: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.028: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.033: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.223: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.233: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.238: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.243: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.248: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.258: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.258: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.263: I/onPostExecute(16646): Аватар отсутствует
08-21 11:55:56.273: I/onPostExecute(16646): Аватар отсутствует


Добавлено через 21 минуту
Вообще-то сейчас исследовал еще раз - баг может вылезать и после контактов, у которых нет аватара. GetView() так-же четыре раза перебирает все верхние элементы...

Добавлено через 2 часа 0 минут
Баг связан с AsyncTask. Кто подскажет, где поправить?
Первый раз с AsyncTask работаю...
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
21.08.2013, 14:18     Непонятный баг в ListView
Посмотрите здесь:

Баг с items при прокручивании ListView - Программирование Android
Суть такая, что выводится список ListView. Там items могут быть двух разных видов(ну тоесть два немного разных Layout) в зависимости от...

непонятный код - Программирование Android
ДОбрый день, подскажите пожалуйста, что тут к чему case MENU_GET_NEXT_PAGE: // increment the startFrom value and...

Непонятный феномен с дебагом - Программирование Android
1) эксцепшин поймать невозможно 2) первый брейкпоинт не срабатывает 3) неправильно обрабатывает условие И главное - раньше всё...

Баг в приложении - Программирование Android
Здравствуйте , нужна помощь в отладке приложения. Вот такая история у меня , обратился к разработчику , которому 5000руб перевел на...

Баг или фича? - Программирование Android
Всем привет. Вот какая интересная штука происходит с жизненным циклом активити. Если выходить из приложения &quot;механической кнопкой&quot; то метод...

Непонятный вылет приложения при установки значения в NumberPicker - Программирование Android
Доброго времени суток. Никак не получается не передать значение, ни получить значения NumberPicker. Программа вылетает при нажатии на...

Баг или фича в работе светового сенсора? - Программирование Android
Всем привет. Недавно ваял приложение, очень простое, оно определяет освещение и исходя из этого включает или выключает фонарик. Вся эта...

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
chizz
979 / 493 / 54
Регистрация: 19.03.2013
Сообщений: 3,079
Записей в блоге: 18
Завершенные тесты: 1
21.08.2013, 14:33     Непонятный баг в ListView #2
можешь в ЛС весь проект скинуть?
Wenceslaus
Android Developer
130 / 130 / 4
Регистрация: 05.07.2013
Сообщений: 205
21.08.2013, 14:40     Непонятный баг в ListView #3
Grafity, всё дело в кеше. Система кеширует элемент контакта и при прокручивании списка верхний, исчезающий элемент, подставляется в низ (вместо нового, появляющегося). Фактически существует всего 5-7 элементов, которые просто меняются местами. Посему, все настройки (текст и изображения) остаются и отображаются в определённый момент. Что бы этого не происходило, поставьте
Java
1
imageView.setImageDrawable(getResources().getDrawable(R.drawable.standart_contact));
как аватар по умолчанию (рядом с именем и номером телефона).
Grafity
59 / 4 / 1
Регистрация: 31.07.2013
Сообщений: 42
21.08.2013, 15:05  [ТС]     Непонятный баг в ListView #4
Цитата Сообщение от Wenceslaus Посмотреть сообщение
Grafity, всё дело в кеше. Система кеширует элемент контакта и при прокручивании списка верхний, исчезающий элемент, подставляется в низ (вместо нового, появляющегося). Фактически существует всего 5-7 элементов, которые просто меняются местами. Посему, все настройки (текст и изображения) остаются и отображаются в определённый момент. Что бы этого не происходило, поставьте
Java
1
imageView.setImageDrawable(getResources().getDrawable(R.drawable.standart_contact));
как аватар по умолчанию (рядом с именем и номером телефона).
По умолчанию у меня установлено это изображение в imageView, оно перебивается все равно.

Тут проблема в неправильной работе AsynkTask. Как-то я его не так вызываю и что-то не так делаю.
chizz
979 / 493 / 54
Регистрация: 19.03.2013
Сообщений: 3,079
Записей в блоге: 18
Завершенные тесты: 1
21.08.2013, 15:10     Непонятный баг в ListView #5
Попробуй вызывать так:

new BitmapAsyncLoad(holder.image).execute((int) p.photo_id);

Вместо двух строчек
BitmapAsyncLoad bmLoad = new BitmapAsyncLoad(holder.image);
bmLoad.execute((int) p.photo_id);

Хотя у меня asynctask как static определен.. да и вообще вряд ли в это дело
Wenceslaus
Android Developer
130 / 130 / 4
Регистрация: 05.07.2013
Сообщений: 205
21.08.2013, 15:12     Непонятный баг в ListView #6
Grafity, где по умолчанию установлено? В xml? Я говорю о программной установке, как в случае с телефоном и именем. Вот так:
Java
1
2
3
holder.name.setText(p.name);
holder.telephone.setText(p.tel);
holder.image.setImageDrawable(getResources().getDrawable(R.drawable.standart_contact));
Grafity
59 / 4 / 1
Регистрация: 31.07.2013
Сообщений: 42
21.08.2013, 15:42  [ТС]     Непонятный баг в ListView #7
Цитата Сообщение от chizz Посмотреть сообщение
Попробуй вызывать так:

new BitmapAsyncLoad(holder.image).execute((int) p.photo_id);

Вместо двух строчек
BitmapAsyncLoad bmLoad = new BitmapAsyncLoad(holder.image);
bmLoad.execute((int) p.photo_id);
Не помогло.

Гугл дает здесь вот такой готовый метод:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Using an AsyncTask to load the slow images in a background thread
new AsyncTask<ViewHolder, Void, Bitmap>() {
    private ViewHolder v;
 
    @Override
    protected Bitmap doInBackground(ViewHolder... params) {
        v = params[0];
        return mFakeImageLoader.getImage();
    }
 
    @Override
    protected void onPostExecute(Bitmap result) {
        super.onPostExecute(result);
        if (v.position == position) {
            // If this item hasn't been recycled already, hide the
            // progress and set and show the image
            v.progress.setVisibility(View.GONE);
            v.icon.setVisibility(View.VISIBLE);
            v.icon.setImageBitmap(result);
        }
    }
}.execute(holder);
Я пока не могу сообразить как это прикрутить к моему проекту. Пробовал - не получилось.
Содержимое моего doInBackground я запихивал туда, это понятно. Но вот не понятно с position.

Добавлено через 5 минут
Цитата Сообщение от Wenceslaus Посмотреть сообщение
Grafity, где по умолчанию установлено? В xml? Я говорю о программной установке, как в случае с телефоном и именем. Вот так:
Java
1
2
3
holder.name.setText(p.name);
holder.telephone.setText(p.tel);
holder.image.setImageDrawable(getResources().getDrawable(R.drawable.standart_contact));
Сделал, но не помогло. Тут явно проблема в асинхронке.
Нашел на ХешКоде очень похожий пример. Там написали несколько решений, но я толком ничего не понял

Добавлено через 19 минут
В идеале, прикрутить бы сюда ImageLoader и бед не знать, но я не знаю, как подсунуть ему битмапы.
V0v1k
1158 / 982 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
21.08.2013, 21:07     Непонятный баг в ListView #8
Wenceslaus все правильно сказал, в getView, перед запуском таска, нужно проставлять дефолтную картинку.
еще проблемы могут быть если долго загружается картинка, она может стать неактуальной для ImageView, поэтому нужно в ImageView запихивать p.photo_id методом setTag, а перед вставкой картинки проверять не изменилась ли photo_id.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.08.2013, 11:17     Непонятный баг в ListView
Еще ссылки по теме:

ListView SubItem - Программирование Android
Всем привет! Расскажите пожалуйста как заполнять SubItem в виджете ListView. Мне нужно к обычному Item, который реализован вот так: ...

Изменить ListView - Программирование Android
В начале работы программы заполняется ListView (с помощью setAdapter(adapter); ); Как сделать, чтобы при нажатии кнопки изменился...

отображение Listview - Программирование Android
Необходимо вывести строковый массив(listview_names) и осуществить поиск по его элементам... код получился следующий: public class...

Альтернатива ListView - Программирование Android
Использую ListView Но оказывается его нельзя использовать внутри ScrollView Подскажите какой есть аналог? Чтобы Вывести данные из...

ListView пустой - Программирование Android
Запутался. public class FragmentList extends Fragment implements AdapterView.OnItemClickListener{ private ListView listView; ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Grafity
59 / 4 / 1
Регистрация: 31.07.2013
Сообщений: 42
22.08.2013, 11:17  [ТС]     Непонятный баг в ListView #9
Цитата Сообщение от V0v1k Посмотреть сообщение
Wenceslaus все правильно сказал, в getView, перед запуском таска, нужно проставлять дефолтную картинку.
еще проблемы могут быть если долго загружается картинка, она может стать неактуальной для ImageView, поэтому нужно в ImageView запихивать p.photo_id методом setTag, а перед вставкой картинки проверять не изменилась ли photo_id.
Словил ClassCastExeption...

Java
1
2
3
4
5
6
7
8
9
10
11
public View getView(final int position, View convertView, ViewGroup parent) {
 . . .
holder.name.setText(p.name);
holder.telephone.setText(p.tel);
holder.image.setTag(p.photo_id);
holder.image.setImageDrawable(getResources().getDrawable(R.drawable.standart_contact));
 
new BitmapAsyncLoad(holder.image).execute((int) p.photo_id);
            
return view;
        }
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class BitmapAsyncLoad extends AsyncTask<Integer, Void, Bitmap>{
            
            private final WeakReference<ImageView> imageViewReference;
            private long photo_id;
            
            public BitmapAsyncLoad(ImageView imageView) {
                imageViewReference = new WeakReference<ImageView>(imageView);
            }
 
            @Override
            protected Bitmap doInBackground(Integer... imageDataRow) {
                // TODO Auto-generated method stub
                photo_id = imageDataRow[0];
                Log.d("doInBackground", "Грузим фото. ID = " + photo_id);
                return loadContactPhoto(photo_id);
            }
            
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                
                if (isCancelled()) {
                    Log.i("onPostExecute", "Отмена");
                    bitmap = null;
                }
                
                if (imageViewReference != null && ((String)imageViewReference.get().getTag()).equals(photo_id) && bitmap != null) {
                    imageViewReference.get().setImageBitmap(bitmap);
                    Log.i("onPostExecute", "Установка аватара");
       
                }
 
            }
            
        }
Добавлено через 6 минут
Все! Отбой.

Все шикарно работает!

Немного поменял onPosnExecute()

Java
1
2
3
4
5
6
7
ImageView imageView = imageViewReference.get();
                
                if (imageViewReference != null && imageView.getTag().equals(photo_id) && bitmap != null) {
                    imageViewReference.get().setImageBitmap(bitmap);
                    Log.i("onPostExecute", "Установка аватара");
                    
                }
Добавлено через 13 минут
Всем спасибо большое за помощь!
Yandex
Объявления
22.08.2013, 11:17     Непонятный баг в ListView
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru