How to avoid image flickering in a listview

前端 未结 5 1098
伪装坚强ぢ
伪装坚强ぢ 2021-01-14 02:09

I have a listivew that display a bunch of images. am using Universal Image Loader to load this images from files to imageviews.

This images have dif

相关标签:
5条回答
  • 2021-01-14 02:10

    my suggestion is to use grid view to avoid flickering of images it will load at first time if it is same url , it will load from cache

     Glide.with(mContext)
                .load(item.getImageUrl())
                .into(holder.mIVGridPic);
    
    0 讨论(0)
  • 2021-01-14 02:18

    How I solved it was by creating a Bitmap[] array variable to store images, then in adapter's getView(), I used position to check if image in Bitmap[] array is null or has value. If it is has value, then I use the value instead of calling the new DownloadImageTask() construct again.

    For example:

    YourCustomArrayAdapter.java

    public class MyCustomArrayAdapter extends ArrayAdapter {
       private static Bitmap[] myListViewImageViewsArray = new Bitmap[listViewItemsArray.length];
       private String[] myListViewImageURLsArray = new String[listViewItemsArray.length]{
          "image_url_1",
          "image_url_2",
          ...
          ...
       };
    
    
       @Override
       public View getView(int position, View view, ViewGroup parent){
           CustomViewHolder vHolder;
            if(view == null){
                view = inflater.inflate(R.layout.movies_coming_soon_content_template, null, true);
                vHolder = new CustomViewHolder();
                vHolder.imageView = (AppCompatImageView) view.findViewById(R.id.my_cutom_image);
                vHolder.imageUrl = "";
                view.setTag(vHolder);
            }
            else{
                vHolder = (CustomViewHolder)view.getTag();
                // -- Set imageview src to null or some predefined placeholder (this is not really necessary but it might help just to flush any conflicting data hanging around)
                vHolder.imageView.setImageResource(null);
            }
    
           // ... 
    
    
           // -- THIS IS THE MAIN PART THAT STOPPED THE FLICKERING FOR ME
           if(myListViewImageViewsArray[position] != null){
              vHolder.imageView.setImageBitmap(myListViewImageViewsArray[position]);
           }else{
              new DownloadImageTask(position, vHolder.imageView).execute(vHolder.imageUrl);
           }
           // -- END OF THE FLICKERING CONTROL    
       }
    }
    

    Then, in your image downloader construct, after downloading the image, make an insertion into the Bitmap[] image array for that position. For example:

    YourImageDownloaderClass.java

    public class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
       AppCompatImageView imageView;
       int position;
    
       public DownloadImageTask(int position, AppCompatImageView imageView){
           this.imageView = imageView;
           this.position = position;
       }
    
       @Override
       protected Bitmap doInBackground(String...urls) {
    
           String urlOfImage = urls[0];
           Bitmap logo = null;
           try{            
               logo = BitmapFactory.decodeStream((InputStream) new URL(urlOfImage).getContent());
           }catch(Exception e){
               e.printStackTrace();            
           }
           return logo;
       }
    
       @Override
       protected void onPostExecute(Bitmap result){
           if(result != null) {
              YourCustomArrayAdapter.myListViewImageViewsArray [position] = result;
              imageView.setImageBitmap(result);                    
           }else{
              YourCustomArrayAdapter.myListViewImageViewsArray [position] = null;
              imageView.setImageResource(null);                  
           }
        }
    }
    
    0 讨论(0)
  • 2021-01-14 02:20

    The reason for this flicker is that, in listview list items are reused. When re-used, the imageviews in the list item retains the old image reference which is displayed first. Later on once new image is downloaded, it starts to show. this causes the flickering behavior. To avoid this flickering issue, always clear the old image reference from the imageview when it is getting reused.

    In your case, add holder.image.setImageBitmap(null); after holder = (ViewHolder) convertView.getTag();

    So, your getView() method will look like:

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
    
        ...
    
        if (convertView == null) {
            LayoutInflater inflater = getLayoutInflater();
            convertView = inflater.inflate(viewResourceId, null);
    
            holder = new ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
            holder.image.setImageBitmap(null)
        }
    
        ...
    
        return convertView;
    }
    
    0 讨论(0)
  • 2021-01-14 02:21

    After hours of research, i was able to know the method that i can use to calculate new imageview height while maintaining image aspect ratio.

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
    
    //Returns null, sizes are in the options variable
    BitmapFactory.decodeFile("/sdcard/image.png", options);
    int width = options.outWidth;
    int height = options.outHeight;
    
    //calculating image aspect ratio
    float ratio =(float) height/(float) width;
    
    //calculating my image height since i want it to be 360px wide
    int newHeight = Math.round(ratio*360);
    
    //setting the new dimentions
     imageview.getLayoutParams().width = 360;
     imageview.getLayoutParams().height = newHeight;
    
     //i'm using universal image loader to display image
     imaheview.post(new Runnable(){
      ImageLoader.getInstance().displayImage(imageuri,imageview,displayoptions);
     });
    
    0 讨论(0)
  • 2021-01-14 02:28

    You can do something like this :

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    
    //Returns null, sizes are in the options variable
    BitmapFactory.decodeFile("/sdcard/image.png", options);
    int width = options.outWidth;
    int height = options.outHeight;
    //If you want, the MIME type will also be decoded (if possible)
    String type = options.outMimeType;
    
    0 讨论(0)
提交回复
热议问题