Актуализирането на Android ListView на миниатюри на изображения с помощта на AsyncTask причинява рециклиране на изгледа

Опитвам се да накарам миниатюри да работят с AsyncTask за файлове с изображения в ListView. Имам често срещания проблем с рециклирането на редове и по този начин при превъртане миниатюрите се присвояват на грешни редове. Опитах се да добавя тагове към ImageView и след това да потвърдя таговете в onPostExecute() в AsyncTask, но опитите ми обаче бяха неуспешни. Моля, някой да помогне!

Персонализираният адаптер е както следва:

public class MySimpleAdapter extends SimpleAdapter {

        public MySimpleAdapter(Context context,
                List<? extends Map<String, ?>> data, int resource,
                String[] from, int[] to) {
            super(context, data, resource, from, to);
            // TODO Auto-generated constructor stub
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            final View v = super.getView(position, convertView, parent);
            thumbnail = (ImageView) v.findViewById(R.id.thumbnail);
            checker = (CheckBox) v.findViewById(R.id.checkBox);
            filenametext = (TextView) v.findViewById(R.id.text1);
            String pathtoimage = startLocation.concat("/"
                    + filenametext.getText().toString());
            desctext = (TextView) v.findViewById(R.id.text2);
            String temp = desctext.getText().toString();
            if (temp.equals("Directory") == true) {
                checker.setEnabled(false);
                switch (theme) {
                case 0:
                    thumbnail.setImageResource(R.drawable.folder_light);
                    break;
                case 1:
                    thumbnail.setImageResource(R.drawable.folder_dark);
                    break;
                }

            } else {
                checker.setEnabled(true);
                if (filenametext.getText().toString().endsWith(".jpg")
                        || filenametext.getText().toString().endsWith(".png")
                        || filenametext.getText().toString().endsWith(".bmp")) {
                    Boolean hashmapfound = false;
                    for (HashMap.Entry<String, Bitmap> entry : thumbnaillist
                            .entrySet()) {
                        String key = entry.getKey();
                        if (key.equals(filenametext.getText().toString())) {
                            Log.d(TAG, "HashMapKey Found!");
                            thumbnail.setImageBitmap(entry.getValue());
                            hashmapfound = true;
                        }
                    }
                    if (!hashmapfound) {
                        Log.d(TAG, "NO HashMapKey Found! Adding to HashMap!");
                        switch (theme) {
                        case 0:
                            thumbnail
                                    .setImageResource(R.drawable.unknown_image_light);
                            break;
                        case 1:
                            thumbnail
                                    .setImageResource(R.drawable.unknown_image_dark);
                            break;
                        }
                        thumbnail.setTag((filenametext.getText().toString()));
                        new GetBitMaps(thumbnail).execute(pathtoimage,
                                filenametext.getText().toString());
                    }

                } else {
                    switch (theme) {
                    case 0:
                        thumbnail.setImageResource(R.drawable.file_light);
                        break;
                    case 1:
                        thumbnail.setImageResource(R.drawable.file_dark);
                        break;
                    }
                }
            }
            return v;
        }

    }

AsyncTask е както следва:

class GetBitMaps extends AsyncTask<String, Void, Bitmap> {

    private ImageView thumbnail;
    private String imageName;

    public GetBitMaps(ImageView thumb) {
        // TODO Auto-generated constructor stub
        thumbnail = thumb;
    }

    @Override
    protected Bitmap doInBackground(String... pathtoimage) {
        Bitmap bmp = createThumbnail(pathtoimage[0]);
        thumbnaillist.put(pathtoimage[1], bmp);
        imageName = pathtoimage[1];
        return bmp;
    }

    @Override
    protected void onPostExecute(Bitmap bmp) {

        if (((String) thumbnail.getTag()).equals(imageName)) {
            thumbnail.setImageBitmap(bmp);
        }
    }

    private Bitmap createThumbnail(String filepath) {
        Bitmap bmp = BitmapFactory.decodeFile(filepath);
        int w = bmp.getWidth();
        int h = bmp.getHeight();
        if (w > h) {
            w = 80;
            h = 40;
        } else if (w < h) {
            w = 40;
            h = 80;
        }
        bmp = Bitmap.createScaledBitmap(bmp, w, h, true);

        return bmp;
    }
}

Все още не мога да разбера какво друго да направя, за да накарам миниатюрите да се показват на правилните редове, ДОКАТО ПРЕВЪРТАВАТЕ.

Моля, обърнете внимание: След превъртане настрани от засегнатите редове и превъртане обратно надолу, нещата работят добре, но проблемът с превъртането не изчезва!


person Daksh    schedule 27.07.2012    source източник
comment
Дубликат на stackoverflow.com/q/6081497/403455, stackoverflow.com/q/9832944/403455   -  person Jeff Axelrod    schedule 28.07.2012


Отговори (3)


От тази публикация в блог:

Това, което искате да направите, е да изпълнявате асинхронно всички IO за ред или всяка рутина, свързана с тежък процесор, в отделна нишка. Номерът тук е да направите това и все още да спазвате поведението на ListView за рециклиране. Например, ако изпълните AsyncTask, за да заредите профилна снимка в getView() на адаптера, изгледът, за който зареждате изображението, може да бъде рециклиран за друга позиция, преди AsyncTask да завърши. Така че имате нужда от механизъм, за да знаете дали изгледът не е бил рециклиран, след като приключите с асинхронната операция.

Един прост начин да постигнете това е да прикачите някаква информация към изгледа, който идентифицира кой ред е свързан с него. След това можете да проверите дали целевият ред за изгледа е все още същият, когато асинхронната операция приключи. Има много начини да се постигне това. Ето само опростена скица на един от начините, по които можете да го направите:

public View getView(int position, View convertView,
        ViewGroup parent) {
    ViewHolder holder;

    ...

    holder.position = position;

    new ThumbnailTask(position, holder)
            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);

    return convertView;
}

private static class ThumbnailTask extends AsyncTask {
    private int mPosition;
    private ViewHolder mHolder;

    public ThumbnailTask(int position, ViewHolder holder) {
        mPosition = position;
        mHolder = holder;
    }

    @Override
    protected Cursor doInBackground(Void... arg0) {
        // Download bitmap here
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (mHolder.position == mPosition) {
            mHolder.thumbnail.setImageBitmap(bitmap);
        }
    }
}

private static class ViewHolder {
    public ImageView thumbnail;
    public int position;
}
person Jeff Axelrod    schedule 28.07.2012
comment
Благодаря много! методът ViewHolder сега работи перфектно. Трябва да съм правил нещо нередно преди! но сега основната грижа е, че когато превъртя и растерните изображения са създадени, те не се присвояват на съответния ред, освен ако не превъртя реда извън екрана и след това отново обратно! има ли някакъв метод, с който бих могъл да анкетирам изгледа и да присвоя растерните изображения, използвайки HashMap на името на файла и неговото растерно изображение, създадено в AsyncTask? вашата помощ ще бъде наистина оценена от мен! Благодаря отново! - person Daksh; 29.07.2012
comment
Не съм сигурен какво може да причини този нов проблем; Предлагам ви да публикувате нов въпрос за това. Но намерих по-добра реализация, която може да можете да използвате от Блог за разработчици на Android. Пълният демонстрационен проект е тук. - person Jeff Axelrod; 29.07.2012
comment
Джеф, можеш ли да публикуваш цялата функция getView()? Опитвам се да го внедря и само първият елемент на ListView се актуализира, изглежда, че имам проблем с повторното използване на изгледите - person steve_patrick; 31.10.2013
comment
Трябва ли да рециклирате/изхвърлите растерното изображение, ако не е правилната mPosition в onPostExecute? - person Matthias; 13.05.2014
comment
какво е курсор? и какво връщане? - person ; 07.03.2016

Използването на AsyncTask.THREAD_POOL_EXECUTOR ще доведе до изпълнение на множество нишки за извличане на миниатюрите. Няма ред в начина, по който те стартират или завършват и задават изображението за изгледа. Когато превъртате напред и назад, може да се окажете с грешни изображения в изгледите си.

Тествах AsyncTask.THREAD_POOL_EXECUTOR и той наистина води до грешно изображение за някои изгледи.

person user1439970    schedule 26.06.2013

можете да опитате да прехвърлите ListView във вашия конструктор на адаптер от вашата дейност (може дори да бъде във вашата асинхронна задача, зависи как искате да я приложите). и сравнете позицията с помощта на getFirstVisiblePosition() и getLastVisiblePosition() спрямо вашите mPosition

person Pete    schedule 18.01.2013