解决自定义图库图片缩略图显示错乱的问题

解决自定义图库加载图片时,缩略图显示错乱的问题。

问题描述:
自定义图库里的图片缩略图显示重复,且有些位置显示空白。
出问题的代码如下:

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            String path = mImageInfos.get(position).getPath();
            Holder holder = null;
            if(convertView == null){
                holder = new Holder();
                convertView = mInflater.inflate(R.layout.picture_item, parent, false);
                holder.imageView = (ImageView) convertView.findViewById(R.id.iv_picture_item);
                holder.checkBox  = (CheckBox) convertView.findViewById(R.id.cb_picture_item);
                //convertView.setLayoutParams(new AbsListView.LayoutParams(mGridWidth, mGridHeight));
                convertView.setTag(holder);
                ***holder.imageView.setTag(path);***
            }else{
                holder = (Holder) convertView.getTag();
            }
            setImageView(path, holder.imageView);

            holder.checkBox.setChecked(false);

            if (mIsSingleChoice) {
                if (position == mChoiceIndex) {
                    holder.checkBox.setChecked(true);
                }
            } else {
                if (mChecked.contains(position)) {
                    holder.checkBox.setChecked(true);
                }
            }
            return convertView;
        }

其中出问题代码在 holder.imageView.setTag(path); 因为在 convertView == null 时才会执行到该行代码,而当convertView 不为Null 时,执行不到此行代码,会复用上次设置的TAG,这样就会照成图片显示一样的问题。正确的做法是将 holder.imageView.setTag(path); 放到if else 之外执行,为每个View都设置一个不同的TAG标识,在使用的时候每个View取到的TAG都不一样,图片显示才不会重复。


正确的代码应该如下:

@Override
        public View getView(int position, View convertView, ViewGroup parent) {
            String path = mImageInfos.get(position).getPath();
            Holder holder = null;
            if(convertView == null){
                holder = new Holder();
                convertView = mInflater.inflate(R.layout.picture_item, parent, false);
                holder.imageView = (ImageView) convertView.findViewById(R.id.iv_picture_item);
                holder.checkBox  = (CheckBox) convertView.findViewById(R.id.cb_picture_item);
                //convertView.setLayoutParams(new AbsListView.LayoutParams(mGridWidth, mGridHeight));
                convertView.setTag(holder);

            }else{
                holder = (Holder) convertView.getTag();
            }
            //解决图片缩略图错乱的问题
            Log.d(TAG, "--setTag--path:"+path+"--position:"+position);
            holder.imageView.setTag(path);
            setImageView(path, holder.imageView);

            holder.checkBox.setChecked(false);

            if (mIsSingleChoice) {
                if (position == mChoiceIndex) {
                    holder.checkBox.setChecked(true);
                }
            } else {
                if (mChecked.contains(position)) {
                    holder.checkBox.setChecked(true);
                }
            }
            return convertView;
        }

附上相关代码供参考:


public class FragmentImagesGrid extends Fragment implements View.OnClickListener{
    public static final String TAG = "ImagesGrid";
    public static final boolean DEBUG = true;

    public static final String IMAGES_PATH = "images_path";
    public static final String IMAGES = "images";

    private ArrayList<ImageInfo> mImageInfos;

    private Context mContext; 

    private ImagesAdapter mAdapter;

    private GridView mGridView;

    private ImageButton mIbtSend;

    private TextView mTvNumber;

    private LayoutInflater mInflater;
    //we save the checked info to the list
//  private SparseBooleanArray mChecked;
    private List<Integer> mChecked;


    private int mGridWidth;
    private int mGridHeight;

    private ArrayList<ImageInfo> mResultInfos;

    private boolean mIsSingleChoice = true;

    private int mChoiceIndex = -1;

    private ViewGroup mDialogView;

    private ImageView mIvDialogPre;

    private Button mBtDialogOk;
    private Button mBtDialogCancel;
    //private SoftReference<Bitmap> mDrawable = null;
    private Bitmap mBitmap;

    private Dialog mImageDialog;

    private final int MAX_SUM = 9; //单次最多可发送图片的数量

    @SuppressWarnings("unchecked")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // 
        super.onCreate(savedInstanceState);
        if(getArguments() != null){
            mImageInfos = (ArrayList<ImageInfo>) getArguments().get(FragmentImagesList.IMAGES_LIST);
        }else{
            mImageInfos = new ArrayList<ImageInfo>();
        }
        mResultInfos = new ArrayList<ImageInfo>();
        mContext  = getActivity();  
        mInflater = LayoutInflater.from(mContext); 
//      mChecked  = new SparseBooleanArray();
        mChecked  = new ArrayList<Integer>();
        mGridWidth  = getActivity().getWindow().getDecorView().getWidth()/3;
        mGridHeight = mGridWidth;

        //createDialog();
    }

    private void createDialog() {
        mImageDialog = new Dialog(getActivity(), R.style.AletDialogFullScreen);
        mDialogView  = (ViewGroup) mInflater.inflate(R.layout.image_dialog, null, false);
        mIvDialogPre = (ImageView) mDialogView.findViewById(R.id.iv_image_dialog);
        mBtDialogOk  = (Button) mDialogView.findViewById(R.id.bt_select_ok);
        mBtDialogCancel = (Button) mDialogView.findViewById(R.id.bt_select_cancel);
        mImageDialog.setContentView(mDialogView);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View layout = inflater.inflate(R.layout.images_grid_fragment, container, false);
        mGridView = (GridView) layout.findViewById(R.id.gv_images);
        mIbtSend  = (ImageButton) layout.findViewById(R.id.ibt_pictrue_send);
        mIbtSend.setOnClickListener(this);
        mTvNumber = (TextView) layout.findViewById(R.id.tv_images_send_number);
        mAdapter  = new ImagesAdapter(mGridView);
        mGridView.setAdapter(mAdapter);
        mGridView.setOnScrollListener(mAdapter);
        mGridView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                if (DEBUG)
                    Log.d(TAG, "item click xxxxxxxxxxx");
                previewImage(position);
            }
        });
        if(DEBUG)
            Log.d(TAG, "grid view width and height"+mGridView.getMeasuredHeight()+"//"+mGridView.getMeasuredWidth());

        return layout;
    }
    /**preview show a image
     * @param position the index what image have clicked.
     * */
    private void previewImage(int position) {
        if(mDialogView == null){
            createDialog();
        }

        final ImageInfo info = mImageInfos.get(position);
        final String path = info.getPath();
        File file = new File(path);
        if (file != null && file.isFile()) {
            Intent intent = new Intent(Intent.ACTION_VIEW);
//          intent.setType("image/*");
            intent.setDataAndType(Uri.fromFile(file), "image/*");
//          intent.setData(Uri.fromFile(file));
//          intent.setType("image/*");
            try {
                startActivity(intent);
            } catch(Exception e) {
                Log.d(TAG, "Failed to open image in photo. " + e.getMessage());
            }
        }
//      imageLoader.displayImage("file://" + path, mIvDialogPre, options, null, null);
//       final int index = position;
//       BitmapFactory.Options options = new BitmapFactory.Options();
//       options.inSampleSize = 8;
//       mBitmap = BitmapFactory.decodeFile(path, options);
//       //mDrawable = new SoftReference<Bitmap>(bitmap);
//       mIvDialogPre.setImageBitmap(mBitmap);
//      
//      mImageDialog.show();
//      mBtDialogOk.setOnClickListener(new OnClickListener() {
//          
//          @Override
//          public void onClick(View v) {
//              if(mIsSingleChoice){
//                  mChoiceIndex = index;
//              }else{
//                  mResultInfos.add(info);
//                  mChecked.put(index, true);
//                  mAdapter.updateCheckedCount();  
//                  mAdapter.notifyDataSetChanged();    
//              }
//              mImageDialog.dismiss();
//              //dialog.getWindow().
//          }
//      });
//      mBtDialogCancel.setOnClickListener(new OnClickListener() {
//          
//          @Override
//          public void onClick(View v) {
//              if(mIsSingleChoice){
//                  mChoiceIndex = -1;
//              }else{
//                  mResultInfos.remove(info);
//                  mChecked.delete(index);
//                  mAdapter.updateCheckedCount();                      
//              }   
//              mImageDialog.dismiss();
//          }
//      });
//      mImageDialog.setOnDismissListener(new OnDismissListener() {
//          
//          @Override
//          public void onDismiss(DialogInterface dialog) {
//              //mDrawable = null;
//              recycler();
//          }
//      }); 
    }

    protected void recycler() {
        // first we need set the source null that make mBitmap no uesed. then
        // recycle it.
//      Log.d(TAG, "recycle");
//      mIvDialogPre.setImageBitmap(null);
//      mBitmap.recycle();
//      //mBitmap = null;
//      Log.d(TAG, "the image Source "+ mBitmap +" df"+mIvDialogPre.getDrawable()+" is recycle"+mBitmap.isRecycled());
    }

    /**
     * the adapter for gird view
     * */
    private class ImagesAdapter extends BaseAdapter implements OnScrollListener {
         /** 
         * 记录所有正在下载或等待下载的任务。 
         */  
        private Set<BitmapWorkerTask> taskCollection;  

        /** 
         * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。 
         */  
        private LruCache<String, Bitmap> mMemoryCache;      

        /** 
         * 第一张可见图片的下标 
         */  
        private int mFirstVisibleItem;  

        /** 
         * 一屏有多少张图片可见 
         */  
        private int mVisibleItemCount;  

        /** 
        * 记录是否刚打开程序,用于解决进入程序不滚动屏幕,不会下载图片的问题。 
        */  
        private boolean isFirstEnter = true; 

        private GridView mImagesGrid;



        public ImagesAdapter(GridView gridView) {
            mImagesGrid = gridView;
            taskCollection = new HashSet<BitmapWorkerTask>();  
            // 获取应用程序最大可用内存  
            int maxMemory = (int) Runtime.getRuntime().maxMemory();  
            int cacheSize = maxMemory /6;  
            // 设置图片缓存大小为程序最大可用内存的1/6  
            mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {  
               @Override  
               protected int sizeOf(String key, Bitmap bitmap) {  
                    return bitmap.getByteCount();  
               }  
           };
        }

        @Override
        public int getCount() {
            //
            return mImageInfos.size();
        }

        @Override
        public Object getItem(int position) {
            //
            return mImageInfos.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            String path = mImageInfos.get(position).getPath();
            Holder holder = null;
            if(convertView == null){
                holder = new Holder();
                convertView = mInflater.inflate(R.layout.picture_item, parent, false);
                holder.imageView = (ImageView) convertView.findViewById(R.id.iv_picture_item);
                holder.checkBox  = (CheckBox) convertView.findViewById(R.id.cb_picture_item);
                //convertView.setLayoutParams(new AbsListView.LayoutParams(mGridWidth, mGridHeight));
                convertView.setTag(holder);

            }else{
                holder = (Holder) convertView.getTag();
            }
            //解决图片缩略图错乱的问题
            Log.d(TAG, "--setTag--path:"+path+"--position:"+position);
            holder.imageView.setTag(path);
            setImageView(path, holder.imageView);

            holder.checkBox.setChecked(false);

            if (mIsSingleChoice) {
                if (position == mChoiceIndex) {
                    holder.checkBox.setChecked(true);
                }
            } else {
                if (mChecked.contains(position)) {
                    holder.checkBox.setChecked(true);
                }
            }


            final int index = position;
            final CheckBox box = holder.checkBox;


            holder.checkBox.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View arg0) {
                    if (checkPictureIsOutLimitSize(index)) {
                        if(mIsSingleChoice){
                            if(box.isChecked()){
                                mChoiceIndex = index;
                            }else{
                                mChoiceIndex = -1;
                            }
                            notifyDataSetChanged();                     
                        }else{
                            if(box.isChecked()){
                                saveCheckedToArray(index);
//                              mChecked.put(index, true);
                            }else{
//                              mChecked.delete(index);
                                if(mChecked.contains(index)){
                                    mChecked.remove(mChecked.indexOf(index));
                                }
                            }
                            updateCheckedCount();
                        }
                    }else {
                        box.setChecked(false);
                        notifyDataSetChanged();
                        Toast.makeText(getActivity(), R.string.file_size_too_large,Toast.LENGTH_SHORT).show();
                    }


                }
            });
            return convertView;
        }

        private class Holder{
            ImageView imageView;
            CheckBox  checkBox;
        }
        /**
         * check whether current picture is more than 20M
         * @param position 
         */
        private boolean checkPictureIsOutLimitSize(int position){
            String path = mImageInfos.get(position).getPath();
            File imageFile= new File(path);         
            long imageFileSize=imageFile.getAbsoluteFile().length();            
            if (imageFileSize<20*1024*1024L) {
                return true;
            }else{
                return false;
            }

        }

        public void setImageView(String path,ImageView imageView){
            Bitmap bitmap = getBitmapFromMemoryCache(path);
            if(bitmap != null){
                imageView.setImageBitmap(bitmap);
            }else{
                imageView.setImageResource(R.drawable.message_picture);
            }   
        }
        public Bitmap getBitmapFromMemoryCache(String key){
            return mMemoryCache.get(key); 
        }

        public void addBitmapToMemoryCache(String key, Bitmap bitmap) {  
            if (getBitmapFromMemoryCache(key) == null) {                
                mMemoryCache.put(key, bitmap);  
            }  
        }  

        /** 
         * 加载Bitmap对象。此方法会在LruCache中检查所有屏幕中可见的ImageView的Bitmap对象, 
         * 如果发现任何一个ImageView的Bitmap对象不在缓存中,就会开启异步线程去下载图片。 
         *  
         * @param firstVisibleItem 
         *            第一个可见的ImageView的下标 
         * @param visibleItemCount 
         *            屏幕中总共可见的元素数 
         */  
         private void loadBitmaps(int firstVisibleItem, int visibleItemCount) { 
             //标准
             try {               
                 for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) { 
                     String path = mImageInfos.get(i).getPath();  
                     Bitmap bitmap = getBitmapFromMemoryCache(path);  
                     if (bitmap == null) {       
                         BitmapWorkerTask task = new BitmapWorkerTask();  
                         taskCollection.add(task);  
                         task.execute(path);  
                     }else{
                         ImageView imageView = (ImageView) mImagesGrid.findViewWithTag(path);  
                         if (imageView != null && bitmap != null) {                                                          
                             imageView.setImageBitmap(bitmap);  
                         }  
                     }  
                 }  
               } catch (Exception e) {  
                    e.printStackTrace();  
              }    
         }                  
         class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {    
             /** 
              * 图片的URL地址 
              */  
             private String path;

             @Override  
             protected Bitmap doInBackground(String... params) { 
                   path = params[0];  
                        // 在后台开始下载图片  
                   Bitmap bitmap = createBitmapFromFile(path);  
                   if (bitmap != null) { 
                       // 图片下载完成后缓存到LrcCache中  
                       addBitmapToMemoryCache(path, bitmap);  
                   }  
                return bitmap;  
            }
            @Override  
            protected void onPostExecute(Bitmap bitmap) {    
                super.onPostExecute(bitmap);  
                // 根据Tag找到相应的ImageView控件,将下载好的图片显示出来。  
                ImageView imageView = (ImageView) mGridView.findViewWithTag(path);  
                if (imageView != null && bitmap != null) {
                    imageView.setImageBitmap(bitmap);  
                }  
                taskCollection.remove(this);  
            }
            /**
             * get bitmap from sdcardfile
             * */
            private Bitmap createBitmapFromFile(String path){
                Options opts = new Options();
                opts.inJustDecodeBounds = true; 
                opts.inInputShareable = true;
                opts.inPurgeable = true;
                opts.inPreferredConfig = Bitmap.Config.RGB_565;
                BitmapFactory.decodeFile(path, opts);
                int imageHeight = opts.outHeight;
                int imageWidth  = opts.outWidth;
                int sampleSize  = getSampleSize(imageWidth,imageHeight);
                opts.inJustDecodeBounds = false;
                opts.inSampleSize = sampleSize;
                return BitmapFactory.decodeFile(path, opts);
            }
            private int getSampleSize(int width,int height){
                int inSampleSize = 1;               
                if(width > mGridWidth || height > mGridHeight){
                    int widthRatio  = Math.round((float)width/mGridWidth);
                    int heightRatio = Math.round(height/mGridHeight);                   
                    inSampleSize =(widthRatio > heightRatio )? widthRatio : heightRatio;                    
                }                               
                return inSampleSize;
            }   
         }
         /** 
          * 取消所有正在下载或等待下载的任务。 
          */  
        public void cancelAllTasks() {  
             if (taskCollection != null) {  
                 for (BitmapWorkerTask task : taskCollection) {  
                     task.cancel(false);  
                   }  
                }  
        } 
        @Override  
        public void onScrollStateChanged(AbsListView view, int scrollState) {  
            // 仅当GridView静止时才去下载图片,GridView滑动时取消所有正在下载的任务  
            if (scrollState == SCROLL_STATE_IDLE) {  
                loadBitmaps(mFirstVisibleItem, mVisibleItemCount);  
            } else {  
              cancelAllTasks();  
            }  
       }   
       @Override  
       public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,  
               int totalItemCount) {  
           Log.d("missyou", "on scroll view the firstVisibleItem "+firstVisibleItem+"visible Item"+visibleItemCount);
           mFirstVisibleItem = firstVisibleItem;  
           mVisibleItemCount = visibleItemCount;  
           // 下载的任务应该由onScrollStateChanged里调用,但首次进入程序时onScrollStateChanged并不会调用,  
           // 因此在这里为首次进入程序开启下载任务。  
           if (isFirstEnter && visibleItemCount > 0) {
               loadBitmaps(mFirstVisibleItem, mVisibleItemCount);  
               isFirstEnter = false;  
           }  
       }  
    }





    protected void updateCheckedCount() {
        if(mChecked.size() == 0){
            mTvNumber.setText("");
            mIbtSend.setClickable(false);
        }else{
            mIbtSend.setClickable(true);
            mTvNumber.setText("("+String.valueOf(mChecked.size())+")");
        }

    }
    @SuppressWarnings("unchecked")
    public void changedData(Bundle peekData) {
        mImageInfos = (ArrayList<ImageInfo>) peekData.get(FragmentImagesList.IMAGES_LIST);
        if(mAdapter != null)
            mAdapter.notifyDataSetChanged();
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.ibt_pictrue_send:


            finishActivityOnresult();
            break;

        default:
            break;
        }

    }
    private void finishActivityOnresult() {         
        if(mIsSingleChoice){
            if(mChoiceIndex == -1){
                return;
            }   
            mResultInfos.add(mImageInfos.get(mChoiceIndex));
        }else{
            if(mChecked.size() == 0){
                return;
            }           
            for(int i =0 ;i<mChecked.size();i++){
                int positon = mChecked.get(i);
                if(DEBUG)
                    Log.d(TAG, "we check item position"+positon);
                mResultInfos.add(mImageInfos.get(positon));
            }
        }   
        if(DEBUG){
            if(mIsSingleChoice){
                Log.d(TAG, "the result image path is"+mImageInfos.get(mChoiceIndex).getPath());
            }
        }

        Intent data = new Intent();
        //Bundle bundle = new Bundle();
        //bundle.putSerializable(IMAGES_PATH, mResultInfos);
        //data.putSerializable(IMAGES_PATH, mResultInfos);
        data.putExtra(IMAGES_PATH, mResultInfos);
        getActivity().setResult(Activity.RESULT_OK, data);
        getActivity().finish();
    }   
    /**
     * set whether we just choice single image.
     * */
    public void setSingleChoice(boolean isSingle){
        this.mIsSingleChoice = isSingle;
    }
    /**
     * check whether current checked Picture's Number is more than MAX_SUM
     * @return true ,more than MAX_SUM; false otherwise
     */
    private boolean checkPictureNumberIsMoreThanMaxSum(){
        if(mChecked.size() >= MAX_SUM){
            return true;
        }
        return false;
    }
    /**
     * save current index to Array in order
     * @param index ,current index to save
     */
    private void saveCheckedToArray(int index){

        if(checkPictureNumberIsMoreThanMaxSum()){
            MDSVideoCallUtils.showMessage(R.string.image_exceed_max_sum);
            Log.e(TAG, "--saveCheckedToArray--removeindex:"+mChecked.get(0));
            mChecked.remove(0);
            if(mAdapter != null)
                mAdapter.notifyDataSetChanged();
        }
        Log.e(TAG, "--saveCheckedToArray--index:"+index);
        mChecked.add(index);
        updateCheckedCount();
    }


}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值