Форум программистов, компьютерный форум, киберфорум
Программирование Android
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/6: Рейтинг темы: голосов - 6, средняя оценка - 5.00
59 / 4 / 1
Регистрация: 31.07.2013
Сообщений: 42
1

Непонятный баг в ListView

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

Author24 — интернет-сервис помощи студентам
В общем, суть такова:

Имеется список контактов в 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 работаю...
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
21.08.2013, 14:18
Ответы с готовыми решениями:

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

Непонятный баг
Пишу программу на Си++ с использованием Qt и FMOD. Вот место, где глючит (тут только куски кода,...

Непонятный баг при запросе
Подскажите, это баг или что? Выводит 77тыс, а показывает 70тыс

Непонятный баг в правильном коде
Есть ирк-бот на c#, раньше все работало нормально, но теперь стало игнорироваться условие if...

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

Тут проблема в неправильной работе AsynkTask. Как-то я его не так вызываю и что-то не так делаю.
0
993 / 521 / 102
Регистрация: 19.03.2013
Сообщений: 3,114
Записей в блоге: 19
21.08.2013, 15:10 5
Попробуй вызывать так:

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

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

Хотя у меня asynctask как static определен.. да и вообще вряд ли в это дело
0
Android Developer
131 / 131 / 6
Регистрация: 05.07.2013
Сообщений: 205
21.08.2013, 15:12 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));
1
59 / 4 / 1
Регистрация: 31.07.2013
Сообщений: 42
21.08.2013, 15:42  [ТС] 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 и бед не знать, но я не знаю, как подсунуть ему битмапы.
0
1162 / 986 / 1
Регистрация: 28.06.2012
Сообщений: 3,462
21.08.2013, 21:07 8
Wenceslaus все правильно сказал, в getView, перед запуском таска, нужно проставлять дефолтную картинку.
еще проблемы могут быть если долго загружается картинка, она может стать неактуальной для ImageView, поэтому нужно в ImageView запихивать p.photo_id методом setTag, а перед вставкой картинки проверять не изменилась ли photo_id.
1
59 / 4 / 1
Регистрация: 31.07.2013
Сообщений: 42
22.08.2013, 11:17  [ТС] 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 минут
Всем спасибо большое за помощь!
0
22.08.2013, 11:17
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
22.08.2013, 11:17
Помогаю со студенческими работами здесь

Непонятный баг. Вставка в стек
В общем суть. Дан Стек указателей, от него потомок - стек чисел. Задача - распечатать в...

непонятный баг textarea под ie
проверял под ie8 и ff 3 у кого есть другие браузеры под рукой, скиньте результаты в ff 3 все ок ...

Непонятный баг со спрайтом в Unity 2D
Всем доброго времени суток. Разрабатываю двухмерную RTS с видом сверху на движке Unity, и вчера...

Непонятный баг в приложении ASP.Net
Здравствуйте друзья. Это очень странный баг, выскакивает наверно из 100 попыток 1 раз. Есть...


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

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru