图像中重复的ListView图像、ListView

2023-09-04 23:28:50 作者:崾赱の亽涐絕卟留

我已经实现Android应用程序应该从服务器下载图片,并在ListView中显示出来,但是当图像被下载很有意思的事情occures

正如你可以在其中有没有下载是由那些已经被下载了psented重新$ P $视频画面看到的。怎么可能发生?我一直在想这件事近两天。

http://www.youtube.com/watch? V = LXY-HAuJO0o和放大器;配备= youtu.be

这是我的$ C $的ListView适配器的温度。

 公共类MoviesAdapter扩展ArrayAdapter< ParkCinema> {
        私人的ArrayList< ParkCinema> movieDataItems;
        私人活动范围内;

        公共MoviesAdapter(活动的背景下,INT textViewResourceId,ArrayList的< ParkCinema> movieDataItems){
            超(背景下,textViewResourceId,movieDataItems);
            this.context =背景;
            this.movi​​eDataItems = movieDataItems;
        }

        @覆盖
        公共查看getView(INT位置,查看convertView,ViewGroup中父){
            如果(convertView == NULL){
                LayoutInflater VI =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = vi.inflate(R.layout.movi​​e_data_row,NULL);
                }

            ParkCinema电影= movieDataItems.get(位置);

            如果(电影!= NULL){
                        ImageView的ImageView的=(ImageView的)convertView.findViewById(R.id.movi​​e_thumb_icon);
                        字符串URL = movie.poster();

                         如果(网址!= NULL){
                            点阵位图= fetchBitmapFromCache(URL);
                            如果(位图== NULL){
                                新BitmapDownloaderTask(ImageView的).execute(URL);
                            }
                            其他 {
                                imageView.setImageBitmap(位);
                            }
                        }
            }
            返回convertView;
        }

        私人LinkedHashMap的<字符串,位图> bitmapCache =新的LinkedHashMap<字符串,位图>();

        私人无效addBitmapToCache(字符串URL,位图位图){
            如果(位图!= NULL){
                同步(bitmapCache){
                    bitmapCache.put(URL,位图);
                }
            }
        }

        私人位图fetchBitmapFromCache(字符串URL){

            同步(bitmapCache){
                最后的位图位= bitmapCache.get(URL);
                 如果(位图!= NULL){
                    返回的位图;
                }
            }

            返回null;

        }


    私有类BitmapDownloaderTask扩展的AsyncTask<字符串,太虚,位图> {

            私人字符串URL;
            私人最终的WeakReference< ImageView的> imageViewReference;

            公共BitmapDownloaderTask(ImageView的ImageView的){
                imageViewReference =新的WeakReference< ImageView的>(ImageView的);
            }

            @覆盖
            受保护的位图doInBackground(字符串...源){
                URL =源[0];
                位图图像;
                尝试{
                    图像= BitmapFactory.de codeStream(新网址(URL).openConnection()的getInputStream());
                    返回形象;
                    }
                赶上(例外五){Log.e(错误,e.getMessage()); e.printStackTrace();}
                返回null;
                }


            @覆盖
            保护无效onPostExecute(位图位图){
                addBitmapToCache(URL,位图);
                imageViewReference.get()setImageBitmap(位图)。
            }
        }
    }
 

编辑3:

 公开查看getView(INT位置,查看convertView,ViewGroup中父){
    如果(convertView == NULL){
        LayoutInflater VI =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.movi​​e_data_row,NULL);
        }
    ParkCinema电影= movieDataItems.get(位置);
    ImageView的ImageView的=(ImageView的)convertView.findViewById(R.id.movi​​e_thumb_icon);
    如果(电影!= NULL){
                字符串URL = movie.poster();

                    如果(网址!= NULL){
                        点阵位图= fetchBitmapFromCache(URL);
                        如果(位图== NULL){
                            imageView.setImageResource(R.drawable.no_image);
                            新BitmapDownloaderTask(ImageView的).execute(URL);
                        }
                        其他 {
                            imageView.setImageBitmap(位);
                        }
                    }
                    其他 {
                        imageView.setImageResource(R.drawable.no_image);
                    }
                }
                其他 {
                    imageView.setImageResource(R.drawable.no_image);
                }

    返回convertView;

}
 
C 中ListView显示图片下面的文字

解决方案

啊哈!我想我可能知道的问题。现在,你的 getView 方法设置你的的ImageView 是这样的:

在获取电影目标的位置 抽影片的缩略图网址 在使用这个URL,它试图在缓存中找到图像 如果它发现的形象,它设置为 如果无法找到图像,它启动一个异步网络请求去得到它,并将它它就会被下载后。

您伊苏斯出现,因为的ListView 重用其行查看秒。当第一个查看滚出屏幕,而不是夸大一个新的,的ListView 通现在屏幕外行的查看作为 convertView 为你重用(这是为了提高效率)。

当你的 getView 得到了 convertView ,这是获得重用,其 ImageView的已设置从以前有它的行,所以你看从屏幕外行的查看的旧形象。根据您当前的 getView 的过程中,您检查新行的形象,并没有找到它在缓存中,它开始请求下载。虽然它正在下载,你看到的旧形象,直到你得到新的形象。

要解决这个问题,你需要确保你设置在该行的查看各个领域马上,以确保你没有任何查看正在展示过期数据。我建议你​​设置的ImageView 为默认的绘制资源(你在设置你的 R.layout.movi​​e_data_row ),而你的网络下载等获取图像。

  @覆盖
公共查看getView(INT位置,查看convertView,ViewGroup中父){
    如果(convertView == NULL){
        LayoutInflater VI =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.movi​​e_data_row,NULL);
    }

    ParkCinema电影= movieDataItems.get(位置);
    ImageView的ImageView的=(ImageView的)convertView.findViewById(R.id.movi​​e_thumb_icon);
    如果(电影!= NULL){
        字符串URL = movie.poster();

        如果(网址!= NULL){
            点阵位图= fetchBitmapFromCache(URL);
            如果(位图== NULL){
                //设置影片缩略图的默认图标正在下载
                //实像
                imageView.setImageResource(R.drawable.movi​​e_thumb_icon);
                新BitmapDownloaderTask(ImageView的).execute(URL);
            }
            其他 {
                //图像设置为我们从缓存中获取的位图
                imageView.setImageBitmap(位);
            }
        }
        其他 {
            //设置影片缩略图的默认图标,因为它没有
            //有一个缩略图网址
            imageView.setImageResource(R.drawable.movi​​e_thumb_icon);
        }
    }
    其他 {
        //设置影片缩略图的默认图标,因为没有
        //此行电影数据
        imageView.setImageResource(R.drawable.movi​​e_thumb_icon);
    }
 

- 编辑 -

更新为更强大,使用绘制。你也有一个问题,你的 BitmapDownloaderTask ,它不处理错误/空。尝试添加这一点。

  @覆盖
保护无效onPostExecute(位图位图){
    addBitmapToCache(URL,位图);
    如果(位图== NULL){
        //设置影片缩略图的默认图标,因为在下载时出错
        。imageViewReference.get()setImageResource(R.drawable.movi​​e_thumb_icon);
    }
    其他 {
        imageViewReference.get()setImageBitmap(位图)。
    }
}
 

I have implemented android app which should download images from server and display them in ListView, but very interesting thing occures while images are downloading

As you can see in video pictures which haven't been downloaded yet are represented by those which have been already downloaded. How that can happen? I've thinking about it almost two days.

http://www.youtube.com/watch?v=lxY-HAuJO0o&feature=youtu.be

here is my code of ListView adapter.

public class MoviesAdapter extends ArrayAdapter<ParkCinema> {
        private ArrayList<ParkCinema> movieDataItems;   
        private Activity context;

        public MoviesAdapter(Activity context, int textViewResourceId, ArrayList<ParkCinema> movieDataItems) {
            super(context, textViewResourceId, movieDataItems);
            this.context = context;
            this.movieDataItems = movieDataItems;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) { 
            if (convertView == null) {
                LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = vi.inflate(R.layout.movie_data_row, null);
                }

            ParkCinema movie = movieDataItems.get(position);

            if (movie!=null){
                        ImageView imageView = (ImageView) convertView.findViewById(R.id.movie_thumb_icon);
                        String url = movie.poster();

                         if (url!=null) {
                            Bitmap bitmap = fetchBitmapFromCache(url);
                            if (bitmap==null) { 
                                new BitmapDownloaderTask(imageView).execute(url);
                            }
                            else {
                                imageView.setImageBitmap(bitmap);
                            } 
                        } 
            }
            return convertView;
        }

        private LinkedHashMap<String, Bitmap> bitmapCache = new LinkedHashMap<String, Bitmap>();

        private void addBitmapToCache(String url, Bitmap bitmap) {
            if (bitmap != null) {
                synchronized (bitmapCache) {
                    bitmapCache.put(url, bitmap);
                }
            }
        }

        private Bitmap fetchBitmapFromCache(String url) {

            synchronized (bitmapCache) {
                final Bitmap bitmap = bitmapCache.get(url);
                 if (bitmap != null) {
                    return bitmap;
                } 
            }

            return null;

        }


    private class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {

            private String url;
            private final WeakReference<ImageView> imageViewReference;

            public BitmapDownloaderTask(ImageView imageView) {
                imageViewReference = new WeakReference<ImageView>(imageView);
            }

            @Override
            protected Bitmap doInBackground (String... source) {
                url = source[0];
                Bitmap image;
                try{
                    image = BitmapFactory.decodeStream(new URL(url).openConnection().getInputStream());
                    return image;
                    }
                catch(Exception e){Log.e("Error", e.getMessage()); e.printStackTrace();}
                return null;
                } 


            @Override
            protected void onPostExecute(Bitmap bitmap) {       
                addBitmapToCache(url, bitmap);
                imageViewReference.get().setImageBitmap(bitmap);               
            }
        }
    }

Edit 3:

public View getView(int position, View convertView, ViewGroup parent) { 
    if (convertView == null) {
        LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
        convertView = vi.inflate(R.layout.movie_data_row, null);
        }
    ParkCinema movie = movieDataItems.get(position);
    ImageView imageView = (ImageView) convertView.findViewById(R.id.movie_thumb_icon);
    if (movie!=null){
                String url = movie.poster();

                    if (url != null) {
                        Bitmap bitmap = fetchBitmapFromCache(url);
                        if (bitmap == null) {
                            imageView.setImageResource(R.drawable.no_image);
                            new BitmapDownloaderTask(imageView).execute(url);
                        }
                        else {
                            imageView.setImageBitmap(bitmap);
                        }
                    }
                    else {
                        imageView.setImageResource(R.drawable.no_image);
                    }
                }
                else {
                    imageView.setImageResource(R.drawable.no_image);
                } 

    return convertView;

}

解决方案

Aha! I think I may know the issue. Right now, your getView method sets your ImageView like this:

Gets movie object at position Pulls out the movie's thumbnail url Using that url, it tries to find the image in the cache If it finds the image, it sets it If it can't find the image, it starts an async network request to go get it, and sets it after it gets downloaded.

Your issus arises since ListView reuses its rows' Views. When the first View scrolls off the screen, rather than inflate a new one, ListView passes the now offscreen row's View in as convertView for you to reuse (this is for efficiency).

When your getView gets a convertView that is getting reused, its ImageView has already been set from the row that had it before, so you see the old image from the offscreen row's View. With your current getView process, you check for the new row's image, and it doesn't find it in the cache, it starts a request to download it. While it is downloading, you see the old image until you get the new image.

To fix this, you need to make sure you set every field in the row's View immediately, to make sure you don't have any Views showing stale data. I would suggest you set the ImageView to the default drawable resource (you have set in your R.layout.movie_data_row) while you wait for the network download to get the image.

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.movie_data_row, null);
    }

    ParkCinema movie = movieDataItems.get(position);
    ImageView imageView = (ImageView) convertView.findViewById(R.id.movie_thumb_icon);
    if (movie != null) {
        String url = movie.poster();

        if (url != null) {
            Bitmap bitmap = fetchBitmapFromCache(url);
            if (bitmap == null) {
                // Set the movie thumbnail to the default icon while we load
                // the real image
                imageView.setImageResource(R.drawable.movie_thumb_icon);
                new BitmapDownloaderTask(imageView).execute(url);
            }
            else {
                // Set the image to the bitmap we get from the cache
                imageView.setImageBitmap(bitmap);
            }
        }
        else {
            // Set the movie thumbnail to the default icon, since it doesn't
            // have a thumbnail URL
            imageView.setImageResource(R.drawable.movie_thumb_icon);
        }
    }
    else {
        // Set the movie thumbnail to the default icon, since there's no
        // movie data for this row
        imageView.setImageResource(R.drawable.movie_thumb_icon);
    }

-Edit-

Updated to be even more robust, using your drawable. You also have an issue with your BitmapDownloaderTask, it does not handle errors/null. Try adding this as well.

@Override
protected void onPostExecute(Bitmap bitmap) { 
    addBitmapToCache(url, bitmap);
    if (bitmap == null) {
        // Set the movie thumbnail to the default icon, since an error occurred while downloading
        imageViewReference.get().setImageResource(R.drawable.movie_thumb_icon);
    }
    else {
        imageViewReference.get().setImageBitmap(bitmap);
    }            
}

 
精彩推荐
图片推荐