Обновление представления списка Android - PullRequest
2 голосов
/ 16 марта 2012

Я изо всех сил пытаюсь обновить представление списка данными из базы данных, это прекрасно работает с помощью SimpleCursorAdapter.Но представление изображения в строках не обновляется при запуске упражнения, мне приходится несколько раз прокручивать список, и только после этого изображения загружаются в представление изображения.

Это средство связывания, которое я используюдля SimpleCursorAdapter:

 private class PromotionViewBinder implements SimpleCursorAdapter.ViewBinder {
            private int done;
            public boolean setViewValue(View view, Cursor cursor, int index) {
                Log.e(""+cursor.getCount(),"");
                View tmpview = view;

                 if (index == cursor.getColumnIndex(PromotionsTable.SEEN_COL)) {
                     boolean read = cursor.getInt(index) > 0 ? true : false;
                     TextView title = (TextView) tmpview;
                     if (!read) {
                         title.setTypeface(Typeface.DEFAULT_BOLD, 0);
                     } else {
                         title.setTypeface(Typeface.DEFAULT);
                     }
                     return true;
                 }  else if (tmpview.getId() == R.id.promotions_list_row_image){
                        String imageURL = cursor.getString(index);
                        Log.e("",imageURL);
                        imageRetriever.displayImage(imageURL, (ImageView)tmpview);
                        return true;
                } else {
                     return false;
                 }
             }
         }

Класс получения изображений - это пример LazyList отсюда .Как вы увидите, это использует runnable для извлечения изображений, и после того, как задача выполнена, автоматически обновляет данный imageView ... Как вы думаете, ссылка на imageView потеряна где-то на пути?

Заранее спасибо, Ник

package com.tipgain.promotions;

Класс получения изображений:

/**
 * This class is used for retrieving images from a given web link. it uses local
 * storage and memory to store the images. Once a image is downloaded
 * successfully the UI gets updated automatically.
 * 
 * 
 */
public class ImageRetriever {
    private final String TAG = ImageRetriever.class.getName();

    private MemoryImageCache memoryImgCache = new MemoryImageCache();
    private LocalStorageImageCache localFileCache;
    private Map<ImageView, String> imageViewHolders = Collections
            .synchronizedMap(new WeakHashMap<ImageView, String>());
    private ExecutorService execService;
    final int defaultImageID = R.drawable.photo_not_available;

    public ImageRetriever(Context context) {
        localFileCache = new LocalStorageImageCache(context);
        execService = Executors.newFixedThreadPool(5);
    }

    public void displayImage(String url, ImageView imageView) {
        imageViewHolders.put(imageView, url);
        Bitmap bmp = memoryImgCache.retrieve(url);

        if (bmp != null) {
            Log.e("case 1", " " + (bmp != null));
            imageView.setImageBitmap(bmp);

        } else {
            Log.e("case 2", " " + (bmp == null));
            addImageToQueue(url, imageView);
            imageView.setImageResource(defaultImageID);
        }
    }

    private void addImageToQueue(String url, ImageView imageView) {
        NextImageToLoad img = new NextImageToLoad(url, imageView);
        execService.submit(new ImagesRetriever(img));
    }

    /**
     * This method is used for retrieving the Bitmap Image.
     * 
     * @param url
     *            String representing the url pointing to the image.
     * @return Bitmap representing the image
     */
    private Bitmap getBitmap(String url) {
        File imageFile = localFileCache.getFile(url);

        // trying to get the bitmap from the local storage first
        Bitmap bmp = decodeImageFile(imageFile);
        if (bmp != null)
            return bmp;

        // if the file was not found locally we retrieve it from the web
        try {
            URL imageUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) imageUrl
                    .openConnection();
             conn.setConnectTimeout(30000);
             conn.setReadTimeout(30000);
            conn.setInstanceFollowRedirects(true);
            InputStream is = conn.getInputStream();
            OutputStream os = new FileOutputStream(imageFile);
            Utils.CopyStream(is, os);
            os.close();
            bmp = decodeImageFile(imageFile);
            return bmp;
        } catch (MalformedURLException e) {
            Log.e(TAG, e.getMessage());
        } catch (FileNotFoundException e) {
            Log.e(TAG, e.getMessage());
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
        return null;
    }

    /**
     * This method is used for decoding a given image file. Also, to reduce
     * memory, the image is also scaled.
     * 
     * @param imageFile
     * @return
     */
    private Bitmap decodeImageFile(File imageFile) {
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(imageFile), null,
                    options);

            // Find the correct scale value. It should be the power of 2.
            // Deciding the perfect scaling value. (^2).
            final int REQUIRED_SIZE = 100;
            int tmpWidth = options.outWidth, tmpHeight = options.outHeight;
            int scale = 1;
            while (true) {
                if (tmpWidth / 2 < REQUIRED_SIZE
                        || tmpHeight / 2 < REQUIRED_SIZE)
                    break;
                tmpWidth /= 2;
                tmpHeight /= 2;
                scale *= 2;
            }

            // decoding using inSampleSize
            BitmapFactory.Options option2 = new BitmapFactory.Options();
            option2.inSampleSize = scale;
            return BitmapFactory.decodeStream(new FileInputStream(imageFile),
                    null, option2);
        } catch (FileNotFoundException e) {
            Log.e(TAG, e.getLocalizedMessage());
        }
        return null;
    }

    private boolean reusedImage(NextImageToLoad image) {
        Context c = image.imageView.getContext();
        c.getContentResolver().notifyChange(PromotionsProvider.CONTENT_URI, null);

        String tag = imageViewHolders.get(image.imageView);
        if ((tag == null) || (!tag.equals(image.url)))
            return true;
        return false;
    }

    /**
     * Clears the Memory and Local cache
     */
    public void clearCache() {
        memoryImgCache.clear();
        localFileCache.clear();
    }

    /**
     * This class implements a runnable that is used for updating the promotions
     * images on the UI
     * 
     * 
     */
    class UIupdater implements Runnable {
        Bitmap bmp;
        NextImageToLoad image;

        public UIupdater(Bitmap bmp, NextImageToLoad image) {
            this.bmp = bmp;
            this.image = image;
            Log.e("", "ui updater");
        }

        public void run() {
            Log.e("ui updater", "ui updater");
            if (reusedImage(image))
                return;
            Log.e("nick", "" + (bmp == null) + "     chberugv");
            if (bmp != null){
                image.imageView.setImageBitmap(bmp);
                Context c = image.imageView.getContext();
                c.getContentResolver().notifyChange(PromotionsProvider.CONTENT_URI, null);

            }else
                image.imageView.setImageResource(defaultImageID);

            }
    }

    private class ImagesRetriever implements Runnable {
        NextImageToLoad image;

        ImagesRetriever(NextImageToLoad image) {
            this.image = image;
        }

        public void run() {
            Log.e("images retirever", " images retriever");
            if (reusedImage(image))
                return;
            Bitmap bmp = getBitmap(image.url);
            memoryImgCache.insert(image.url, bmp);
            if (reusedImage(image))
                return;
            UIupdater uiUpdater = new UIupdater(bmp, image);
            Activity activity = (Activity) image.imageView.getContext();
            activity.runOnUiThread(uiUpdater);
            //Context c = image.imageView.getContext();
            //c.getContentResolver().notifyChange(PromotionsProvider.CONTENT_URI, null);


        }
    }

    /**
     * This class encapsulates the image being downloaded.
     * 
     * @author Nicolae Anca
     * 
     */
    private class NextImageToLoad {
        public String url;
        public ImageView imageView;

        public NextImageToLoad(String u, ImageView i) {
            url = u;
            imageView = i;
        }
    }

}

Модифицированный Runnable:

class UIupdater implements Runnable {
    Bitmap bmp;
    NextImageToLoad image;

    public UIupdater(Bitmap bmp, NextImageToLoad image) {
        this.bmp = bmp;
        this.image = image;
    }

    public void run() {
        if (reusedImage(image))
            return;
        if (bmp != null){
            image.imageView.setImageBitmap(bmp);
            Context c = image.imageView.getContext();
            c.getContentResolver().notifyChange(PromotionsProvider.CONTENT_URI, null);

        }else
            image.imageView.setImageResource(defaultImageID);

        }
}

Ответы [ 3 ]

1 голос
/ 16 марта 2012

Это интересный способ сделать то, что вы делаете.Вы пытались расширить простой адаптер курсора?

  1. Что вы делаете, это реализуете ViewHolder и помещаете в него свое изображение.

  2. Затем в ImageRetriever напишите прослушиватель, который будет вызываться после того, как изображение будет готово и извлечено.

  3. Реализация этого прослушивателя в окне просмотра.

  4. Вы создаете представление в getView () и запрашиваете изображение в BindView ().

  5. После загрузки изображениясписок будет обновляться автоматически.

0 голосов
/ 16 марта 2012

Полагаю, вам нужно использовать какой-то обработчик, вызывающий после загрузки изображения, который будет вызывать notifyDataSetChanged для адаптера списка

0 голосов
/ 16 марта 2012

Один из способов сделать это - вызвать notifyDataSetChenged для просмотра списка, а другой - использовать адаптер в качестве переменной-члена, и когда что-то меняется в просмотре списка, вы вызываете функцию, которая назначает новый адаптер listadapter для адаптера-члена. Таким образом, ваш список будет перерисован при изменении.

...