弱引用的场景——解决android gridView加载大量图片的性能问题

              android相册需求中,用gridView来做发现一个问题,性能太差。使用中发现,它必须等所有的图片加载完成,才会一次性显示出来。而在这期间会一直黑屏。

              另外附带再说一个问题,不论你的图片加载的时候有没有进行压缩,如果不做其他处理的话,早晚会因为图片越来越多出现OOM的问题。

              1、解决性能问题,我们可以用线程异步加载,一个imageView一个线程。imageView随着界面的变化可能绑定的图片会发生变换,所以需要记得取消之前的线程。加载新的图片。在这里还有一个很关键的问题,由于adapter的getView是由系统调用的,imageView的生命周期也是系统来控制的,如果我们对它进行了干预,那么我们非但没有优化性能,反而造成了内存泄露。比如系统在某个时刻对某个imageView设成了null。而我们的线程强引用了imageView,并在为imageView加载图片。这个时候这个imageView就不会被垃圾回收器回收,除非我们的线程没有被其他句柄引用以后。

                    为了不干扰android内部对imageView的管控,我们只能在我们的代码中弱引用imageView。

             2、OOM的问题,在线程加载的时候维护一个bitmap的缓存,当页面滑动的时候,将在页面之外的图片用android提供的图片垃圾回收方法recycle()马上销毁。从而释放内存。

             adapter的关键代码

           

        @Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Log.d(TAG, "getView");
		int windowWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth();
        int pad = 4;
        ImageView imageView;
        if(convertView == null){
            imageView = new ImageView(context);
        }
        else{
            imageView = (ImageView)convertView;
        }
        //判断是否有线程在加载该图片,或者该imageView的图片已经改变
        if (cancelPotentialLoad(fullPathImg.get(position), imageView)) {  
            AsyncLoadImageTask task = new AsyncLoadImageTask(imageView);  
            LoadedDrawable loadedDrawable = new LoadedDrawable(task);  
            imageView.setLayoutParams(new GridView.LayoutParams((windowWidth - pad * 12) / 4, (windowWidth - pad * 12) / 4));
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageView.setImageDrawable(loadedDrawable);  
            task.execute(position);  
        } 
        return imageView;
	}

private boolean cancelPotentialLoad(String url,ImageView imageview){  
		//获得该图片是否有线程加载
        AsyncLoadImageTask loadImageTask = getAsyncLoadImageTask(imageview);  

	    if (loadImageTask != null) {  
	        String bitmapUrl = loadImageTask.url;  
	        //虽然该imageview的加载已经存在,但是url不同,取消原加载线程,并且重新加载
	        if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {  
	                loadImageTask.cancel(true);                          
	        } else {  
	            // 相同的url已经在加载中,不需要加载
	            return false;  
	        }  
	    }  
	    //需要加载图片
	    return true;  
	}  

private class AsyncLoadImageTask extends AsyncTask<Integer, Void, Bitmap>{  
            private String url = null;  
            private final WeakReference<ImageView> imageViewReference; //为了不干扰android本身的对象清理,不造成内存泄露,因此使用弱应用保证回收资源
             
            public AsyncLoadImageTask(ImageView imageview) {  
                    super();  
                    imageViewReference = new WeakReference<ImageView>(imageview);  
            }  

            //加载图片
            @Override  
            protected Bitmap doInBackground(Integer... params) {  
                    // TODO Auto-generated method stub  
                    Bitmap bitmap = null;  
                    this.url = fullPathImg.get(params[0]);                          
                    bitmap = BitmapUtil.getCompressBitmap((Activity) context, url,10);
                    cache.put(fullPathImg.get(params[0]), bitmap);                          
                    return bitmap;  
            }  

            @Override  
            protected void onPostExecute(Bitmap resultBitmap) {  
            		//加载完成回收图片
                    if(isCancelled()){  
                            resultBitmap = null;  
                    }  
                    else{
	                    if(imageViewReference != null){  
	                        ImageView imageview = imageViewReference.get();  
	                        AsyncLoadImageTask loadImageTask = getAsyncLoadImageTask(imageview);  
	                        //当前任务
	                        if (this == loadImageTask) {
                        		//显示图片
                                imageview.setImageBitmap(resultBitmap);   
	                        }  
	                    }  
                    }
                    super.onPostExecute(resultBitmap);  
            }                                                          
    }  

private AsyncLoadImageTask getAsyncLoadImageTask(ImageView imageview){  
        if (imageview != null) {  
	        Drawable drawable = imageview.getDrawable();  
	        if (drawable instanceof LoadedDrawable) {  
	                LoadedDrawable loadedDrawable = (LoadedDrawable)drawable;  
	            return loadedDrawable.getLoadImageTask();  
	        }  
	    }  
	    return null;  
	}  
    
    public static class LoadedDrawable extends ColorDrawable{  
        private final WeakReference<AsyncLoadImageTask> loadImageTaskReference; //记录加载该图片的线程 

	    public LoadedDrawable(AsyncLoadImageTask loadImageTask) {  
	    	//默认加载图片,空白
	        super(Color.TRANSPARENT);  
	        loadImageTaskReference = new WeakReference<AsyncLoadImageTask>(loadImageTask);  
	    }  
	
	    public AsyncLoadImageTask getLoadImageTask() {  
	        return loadImageTaskReference.get();  
	    }  
	}  

       销毁屏幕之外的图片

      

public static OnScrollListener getOnScrollListener(final Map<String,Bitmap> cache,final List<String> path){
		
		return new OnScrollListener(){

			@Override
			public void onScroll(AbsListView view, int firstVisibleItem,  
                    int visibleItemCount, int totalItemCount) {
				BitmapUtil.recycleBitmapCaches(0,firstVisibleItem,cache,path);  
				BitmapUtil.recycleBitmapCaches(firstVisibleItem+visibleItemCount,totalItemCount,cache,path);  
			}

			@Override
			public void onScrollStateChanged(AbsListView arg0, int arg1) {
				// TODO Auto-generated method stub
			}
			
		};
		
	}

public static void recycleBitmapCaches(int fromPosition,int toPosition,Map<String,Bitmap> cache,List<String> path){                 
        Bitmap delBitmap = null;  
        for(int del=fromPosition;del<toPosition;del++){  
            delBitmap = cache.get(path.get(del));          
            if(delBitmap != null){                           
                    cache.remove(path.get(del));                 
                    delBitmap.recycle();          
                    delBitmap = null;  
            }  
        }                 
    }  


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值