Асинхронная загрузка изображений на Android - PullRequest
0 голосов
/ 02 февраля 2012

Здравствуйте, коллеги-разработчики:)

Я сделал очень простой сборщик изображений для Android, чтобы загружать и отображать растровые изображения из Интернета в моем приложении, код для него:

public class BitmapFetcher {

    private static HashMap<String, SoftReference<Bitmap>> bitmapCache = new HashMap<String, SoftReference<Bitmap>>();

    public static Bitmap fetchBitmap(String urlString) {
        SoftReference<Bitmap> cachedBitmap = bitmapCache.get(urlString);

        if (cachedBitmap != null && cachedBitmap.get() != null) {
            return cachedBitmap.get();
        }

        try {
            InputStream is = fetch(urlString);

            Bitmap bitmap = BitmapFactory.decodeStream(is);
            SoftReference<Bitmap> softReferencedBitmap = new SoftReference<Bitmap>(bitmap);
            bitmapCache.put(urlString, softReferencedBitmap);

            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void fetchBitmapAsync(final String urlString, final ImageView view) {
        final Handler handler = new Handler() {
            public void handleMessage(Message message) {
                AsyncImageContainer imageContainer = (AsyncImageContainer) message.obj;

                imageContainer.applyImageToView();
            }
        };

        BitmapTaskRunnable asyncImageFetcherTask = new BitmapTaskRunnable(view, urlString, handler);

        new Thread(asyncImageFetcherTask).start();
    }

    public static InputStream fetch(String urlString) throws MalformedURLException, IOException {
        Log.d("BitmapFetcher", "fetch: " + urlString);
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet request = new HttpGet(urlString);
        HttpResponse response = httpClient.execute(request);

        return response.getEntity().getContent();
    }

}

BitmapTaskRunnable.java:

public class BitmapTaskRunnable implements Runnable {

    private ImageView imageView;
    private String imageUrl;
    private Handler handler;

    public BitmapTaskRunnable() {
    }

    public BitmapTaskRunnable(ImageView imageView, String imageUrl, Handler handler) {
        setImageView(imageView);
        setImageUrl(imageUrl);
        setHandler(handler);
    }

    public void run() {
        Bitmap bitmap = BitmapFetcher.fetchBitmap(getImageUrl());

        AsyncImageContainer imageContainer = new AsyncImageContainer(getImageView(), bitmap);

        handler.sendMessage(handler.obtainMessage(0, imageContainer));
    }

    public ImageView getImageView() {
        return imageView;
    }

    public void setImageView(ImageView imageView) {
        this.imageView = imageView;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }

    public Handler getHandler() {
        return handler;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

}

AsyncImageContainer.java:

public class AsyncImageContainer {

    private ImageView imageView;
    private Bitmap bitmap;

    public AsyncImageContainer() {
    }

    public AsyncImageContainer(ImageView imageView, Bitmap bitmap) {
        setImageView(imageView);
        setBitmap(bitmap);
    }

    public void applyImageToView() {
        getImageView().setImageBitmap(getBitmap());
    }

    public ImageView getImageView() {
        return imageView;
    }

    public void setImageView(ImageView imageView) {
        this.imageView = imageView;
    }

    public Bitmap getBitmap() {
        return bitmap;
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
    }

}

Как я уже сказал, он очень простой, с очень простым кэшированием и без создания потоков на создаваемых потоках (этоуже планировалось сделать в ближайшее время).

Ну, в настоящее время я испытываю странное поведение из-за этого, когда мне нужно загрузить изображения в ListView, что я сделал: у меня есть несколько классов, которые расширяют ArrayAdapter и переопределяютgetView для отображения моего макета, когда мне нужно изображение на нем, я буду делать следующее:

BitmapFetcher.fetchBitmapAsync(news.getChannelAvatar(), holder.channelAvatarView);

И это должно начать заставлять BitmapFetcher запускать новый поток, который будет загружать растровое изображение и отправлять сообщениеобработчик к нему применяет изображение к представлению (так как только поток, создавший иерархию представлений, может изменить его).

Все хорошо для 2-го и n-го изображенийeViews в списке, но 1-й результат ВСЕГДА сходит с ума, переходя на изображения, которые были загружены до тех пор, пока все изображения не загрузятся и не установятся.Затем, если я немного перетаскиваю список, пока 1-й результат не исчезнет и не вернется к началу, он отобразит правильное изображение.

Это действительно меня беспокоит, так как я сделал гораздо более простую версию кода (тот, который обработчик обрабатывал непосредственно, помещая растровое изображение в ImageView, Runnable не существовал, это был простой анонимный объект Thread с переопределением run() и т. д.) и пробовал эту версию, думая, что каким-то образом fetchBitmapAsync теряет ссылку на правильныйImageView или что-то в этом роде.

Происходит ли это из-за того, что Android делает для перезарядки представлений внутри ListView?Если нет, в чем может быть причина?Я где-то глуп, и через пару дней, работая над этим кодом, я ослеп?: (

Спасибо за помощь: D

1 Ответ

1 голос
/ 26 мая 2012

Для всей моей загрузки ленивых изображений я использую Prime . У него даже есть пример того, как использовать его в ListView.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...