listview,gridview 动态加载网络图片

        最近在做一个android播放器客户端。需要把服务器上的资源信息拉到手机上显示。这就离不开listview。一开始我举得很容易的,但真正做起来就会出现很多意想不到的问题。比如说listview滑动不流畅,图片加载混乱,甚至会有OOM。等等这些问题我都碰到过,可能我是菜鸟,这些低级的问题都被我碰到了,但我很肯定的说,以后再做类似的事情,问题就迎刃而解了。

        说一下listview 和gridview的区别。其实没有什么区别,我们能理解生活中用到的桶和盆有什么区别,就能理解这两个的区别,同样的容器,只是外表不一样而已。实现方式都会是new 一个adapter出来,然后用listview(gridview).setAdapter(adapter)。再加一些监听之类的就差不多了。

    说了半天,还没进入主题。listview加载网络图片的实现,我有找过很多资料,但用的都不是很符合自己的要求。最后找到了一个高手的code,得以解决之。添加url在此:http://www.cnblogs.com/liongname/articles/2345087.html

文章中只有用到临时缓存,我这里再添加一个存储,保存到sdcard。

首先我们要实现一个异步加载图片的类,用来对listview的每一个item加载图片:

 

public enum BitmapManager {  
    INSTANCE;  
    public static final String TAG = "BitmapManager";
    private final Map<String, SoftReference<Bitmap>> cache;    //对图片做缓存
    private final ExecutorService pool;  
    private Map<ImageView, String> imageViews = Collections  
            .synchronizedMap(new WeakHashMap<ImageView, String>());  
    private Bitmap placeholder;  
  
    BitmapManager() {  
        cache = new HashMap<String, SoftReference<Bitmap>>();  
        pool = Executors.newFixedThreadPool(5);  //线程池
    }  
  
    public void setPlaceholder(Bitmap bmp) {     //设置占位图,如果加载未完成前应该显示的图片
        placeholder = bmp;  
    }  
  
    public Bitmap getBitmapFromCache(String url) {  
        if (cache.containsKey(url)) {  
            return cache.get(url).get();  
        }  
  
        return null;  
    }  
  
    public void queueJob(final String url, final ImageView imageView,  
            final int width, final int height) {  
        /* Create handler in UI thread. */  
        final Handler handler = new Handler() {  
            @Override  
            public void handleMessage(Message msg) {  
                String tag = imageViews.get(imageView);  
                if (tag != null && tag.equals(url)) {   //根据url对应的ImageView 设置图片显示 
                    if (msg.obj != null) {  
                        imageView.setImageBitmap((Bitmap) msg.obj);  
                    } else {  
                        imageView.setImageBitmap(placeholder);  
                        Log.d(null, "fail " + url);  
                    }  
                }  
            }  
        };  
  
        pool.submit(new Runnable() {  //线程异步load图片 
            @Override  
            public void run() {  
                final Bitmap bmp = downloadBitmap(url, width, height);  
                Message message = Message.obtain();  
                message.obj = bmp;  
                Log.d(null, "Item downloaded: " + url);  
  
                handler.sendMessage(message);  
            }  
        });  
    }  
  
    public void loadBitmap(final String url, final ImageView imageView,  
            final int width, final int height) {  
        imageViews.put(imageView, url);  //对传进来的imageView 和url做关联,防止图片混乱  
        Bitmap bitmap = getBitmapFromCache(url);  
  
        // check in UI thread, so no concurrency issues  
        if (bitmap != null) {  
            Log.d(null, "Item loaded from cache: " + url);  
            imageView.setImageBitmap(bitmap);  
        } else {  
            imageView.setImageBitmap(placeholder);  
            queueJob(url, imageView, width, height);  
        }  
    }  
  
    private Bitmap downloadBitmap(String url, int width, int height) {  
    	Bitmap sdcardFile = getSDCardBitmap(url);   //优先从sdcard中取图片
    	if(sdcardFile != null){
    		sdcardFile = Bitmap.createScaledBitmap(sdcardFile, width, height, true);
    		cache.put(url, new SoftReference<Bitmap>(sdcardFile));   
    		return sdcardFile;
    	}
        try {  
            Bitmap bitmap = BitmapFactory.decodeStream((InputStream) new URL(  
                    url).getContent());  
            bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
            saveSDCardBitmap(url,bitmap); //存入sdcard;
            cache.put(url, new SoftReference<Bitmap>(bitmap));  
            return bitmap;  
        } catch (MalformedURLException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
  
        return null;  
    }  
    
    private void saveSDCardBitmap(String url,Bitmap bm){
    	String filePath = Environment.getExternalStorageDirectory()+"/imagecache/"+url.substring(url.lastIndexOf("/")+1); //从url中取文件名以保存到sdcard,方便取。
    	final File f = new File(filePath);
    	if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
	    	File path = new File(Environment.getExternalStorageDirectory()+"/imagecache");
			if(!path.exists()){
				path.mkdirs();
			}
			try {
				FileOutputStream out = new FileOutputStream(f);
				bm.compress(Bitmap.CompressFormat.PNG, 100, out);
				out.flush();	
				out.close();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}catch(IOException e){
				e.printStackTrace();
 			}
			
	    }
    }
    
    private Bitmap getSDCardBitmap(String url){
    	String filePath = Environment.getExternalStorageDirectory()+"/imagecache/"+url.substring(url.lastIndexOf("/")+1);
    	final File f = new File(filePath);
    	if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){  //sdcard 是否存在
	    	File path = new File(Environment.getExternalStorageDirectory()+"/imagecache");
			if(!path.exists()){
				path.mkdirs();
			}
			if(f.exists()){
					Bitmap tmp = BitmapFactory.decodeFile(filePath);
					return tmp;
			}
	    }
    	return null;
    	
    }
}


这个类写好后,我们就只需要在Adapter中的getView()方法中调用这个类就行了。

下面我们来看getView()方法:

public View getView(int position, View convertView, ViewGroup parent) {
	
	ViewHolder holder;
	if(convertView == null){
		holder = new ViewHolder();
		convertView = mInflater.inflate(R.layout.list_unit,null);  /获取list单元布局
		holder.Image = (ImageView)findViewById(R.id.mImage);
		holder.Title = (TextView)findViewbyId(R.id.mTitle);
		
		convertView.setTag(hodler);//添加标签
	}else{
		holder = convertView.getTag();
	}
	
	if(!mBusy){
		BitmapManager.INSTANCE.setPlaceholder(bm); //设置默认图片
  	BitmapManager.INSTANCE.loadBitmap(url, holder.Image, imageWidth,imageHeight);
	}else{
		holder.Image.setImageBitmap(bm);
	}
	
	return convertView;
}

public static class ViewHolder{   
	ImageViwe Image;
	TextView Title;
}

OnScrollListener mScrollListener = new OnScrollListener() {   //对listview的滚动监听

		@Override
		public void onScrollStateChanged(AbsListView view, int scrollState) {
			switch (scrollState) {
			case OnScrollListener.SCROLL_STATE_FLING:
				ListViewAdapter.this.setFlagBusy(true);
				break;
			case OnScrollListener.SCROLL_STATE_IDLE:
				ListViewAdapter.this.setFlagBusy(false);
				break;
			case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
				ListViewAdapter.this.setFlagBusy(false);
				break;
			default:
				break;
			}
			ListViewAdapter.this.notifyDataSetChanged();
		}

		@Override
		public void onScroll(AbsListView view, int firstVisibleItem,
				int visibleItemCount, int totalItemCount) {

		}
};



protected void setFlagBusy(boolean b) {
		// TODO Auto-generated method stub
		mBusy = b;   //全局变量 mBusy,表示listview是否滚动
}


到这里,我们的ListView异步加载图片的主要工作基本完成。剩下的就是在activity中实例化以及set的工作。这个方法对ListView 和GridView都是通用的。目前我还没有发现有图片混乱,内存溢出,滑动不流畅等问题。当然,再次申明,这里的大部分代码不是我的,我只是拿来优化成了一个适合我自己的东西了。平时都忙着coding,对于很多临时找到的好东西,自己感悟出来的东西(当然很少了),都没有及时记下来,等到需要时又找不到了,不得不说这是一大损失。


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值