Android图片墙实现

在学习了郭霖大神的Android高效加载大图、多图解决方案,有效避免程序OOM  之后,又跟着郭大神学习了照片墙的实现

Android照片墙应用实现,再多的图片也不怕崩溃  使用缓存技术使得加载图片避免了OOM(Out Of Memory),下面是做此次照片墙的思

路和记录

第一步:定义图片数据源

第二步:编写主界面布局,使用GridView

第三步:编写每一个item的布局,使用ImageView

第四步:有数据和GridView,因此也要编写一个适配器类

public class PhotoWallApdater extends ArrayAdapter<String> implements OnScrollListener {
	
	//记录所有正在下载或等待下载的任务,便于一次性中断任务
	private Set<BitMapWorkTask> taskCollection; 
	
	//图片缓存
	private LruCache<String, Bitmap> mMemoryCache;
	
	//获得布局实例
	private GridView mPhotoWall;
	
	//第一个可见的图片下标
	private int mFirstVisibleItem;

	//一屏可见多少图片
	private int mVisibleItemCount;
	
	//记录是否第一次进入程序
	private boolean mIsFirstEnter = true;
	
	public PhotoWallApdater(Context context, int textViewResourceId, String[] objects, GridView photoWall) {
		super(context, textViewResourceId, objects);
		mPhotoWall = photoWall;
		taskCollection = new HashSet<BitMapWorkTask>();
		//设置缓冲区大小
		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		int maxCache = maxMemory / 10;
		
		mMemoryCache = new LruCache<String, Bitmap>(maxCache){

			@Override
			protected int sizeOf(String key, Bitmap bitmap) {
				
				return bitmap.getByteCount();//返回图片个数
			}
			
		};
		
		mPhotoWall.setOnScrollListener(this);
	}
	

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		String imageUrl = getItem(position);
		View view;
		
		if(convertView == null){
			view = LayoutInflater.from(getContext()).inflate(R.layout.photo_layout, null);
		}else {
			view = convertView;
		}
		
		 ImageView photo = (ImageView) view.findViewById(R.id.photo);
		 // 给ImageView设置一个Tag,保证异步加载图片时不会乱序  
		 photo.setTag(imageUrl);
		 setImageView(imageUrl, photo);
		
		return view;
	}


	/** 
     * 给ImageView设置图片。首先从LruCache中取出图片的缓存,设置到ImageView上。如果LruCache中没有该图片的缓存, 
     * 就给ImageView设置一张默认图片。 
     *  
     * @param imageUrl 
     *            图片的URL地址,用于作为LruCache的键。 
     * @param imageView 
     *            用于显示图片的控件。 
     */  

	private void setImageView(String imageUrl, ImageView photo) {
		Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);
		if(bitmap != null){
			photo.setImageBitmap(bitmap);
		}else{
		}
	}
	
	/** 
     * 将一张图片存储到LruCache中。 
     *  
     * @param key 
     *            LruCache的键,这里传入图片的URL地址。 
     * @param bitmap 
     *            LruCache的键,这里传入从网络上下载的Bitmap对象。 
     */ 

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

	/** 
     * 从LruCache中获取一张图片,如果不存在就返回null。 
     *  
     * @param key 
     *            LruCache的键,这里传入图片的URL地址。 
     * @return 对应传入键的Bitmap对象,或者null。 
     */ 
	
	private Bitmap getBitmapFromMemoryCache(String key) {
		Bitmap bitmap = mMemoryCache.get(key);
		return bitmap;
	}


	@Override  
    public void onScrollStateChanged(AbsListView view, int scrollState) {  
        // 仅当GridView静止时才去下载图片,GridView滑动时取消所有正在下载的任务  
        if (scrollState == SCROLL_STATE_IDLE) {  
            loadBitmaps(mFirstVisibleItem, mVisibleItemCount);  
        } else {  
            cancleAllTasks();  
        }  
    }  
  
    @Override  
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,  
            int totalItemCount) {  
    	mFirstVisibleItem = firstVisibleItem;
    	mVisibleItemCount = visibleItemCount;  
        // 下载的任务应该由onScrollStateChanged里调用,但首次进入程序时onScrollStateChanged并不会调用,  
        // 因此在这里为首次进入程序开启下载任务。  
        if (mIsFirstEnter && (visibleItemCount > 0)) {  
            loadBitmaps(firstVisibleItem, visibleItemCount);  
            mIsFirstEnter = false;  
        }  
    }  
  
    /** 
     * 加载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 imageUrl = Images.imageUrls[i];  
                Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);  
                if (bitmap == null) {  
                    BitMapWorkTask task = new BitMapWorkTask();  
                    taskCollection.add(task);  
                    task.execute(imageUrl);  
                } else {  
                    ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl);  
                    if (imageView != null && bitmap != null) {  
                        imageView.setImageBitmap(bitmap);  
                    }  
                }  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
	
	public void cancleAllTasks() {
		if(taskCollection != null){
			for(BitMapWorkTask task : taskCollection){
				task.cancel(false);
			}
		}
		
	}
	
	
	class BitMapWorkTask extends AsyncTask<String, Void, Bitmap>{
		
		private String imageUrl;

		@Override
		protected Bitmap doInBackground(String... params) {
			imageUrl = params[0];
			Bitmap bitmap = downloadBitmap(imageUrl);
			
			if(bitmap != null){
				//如果下载图片成功,就把它放入缓冲区
				addBitmapFromMemoryCache(imageUrl, bitmap);
			}
			//把值返回到onPostExecute,更新主线程UI
			return bitmap;
		}
		

		@Override
		protected void onPostExecute(Bitmap result) {
			super.onPostExecute(result);
			
			ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl);
			
			if(imageView != null && result != null){
				imageView.setImageBitmap(result);
			}
			
			taskCollection.remove(this);
		}



		private Bitmap downloadBitmap(String imageUrl) {
			
			Bitmap bitmap = null;
			HttpURLConnection conn = null;//如何判断哪些需要初始化哪些不需要初始化
			InputStream is = null;
			ByteArrayOutputStream baos = null;
			try {
				URL url = new URL(imageUrl);
				conn = (HttpURLConnection) url.openConnection();
				conn.setReadTimeout(5000);
				conn.setConnectTimeout(5000);
				is = conn.getInputStream();
				
				
				/*
				 * byte方式
				 */
//				int len = -1;
//				byte[] buf = new byte[1024];
//				baos = new ByteArrayOutputStream();
//				
//				while((len = is.read(buf)) != -1){//is.read字节读取,读入缓冲区数组buf中
//					baos.write(buf, 0, len);//把数组写入字节数组buf中
//				}
//				baos.flush();
//				
//				byte[] data = baos.toByteArray();
//				
//				bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
				
				
				/*
				 * stream方式
				 */
				
				bitmap = BitmapFactory.decodeStream(is);
				
				Log.d("TAG", "downloadBitmap调用了");
			
			} catch (Exception e) {
				e.printStackTrace();		
			} finally{
				if(conn != null){
					conn.disconnect();
				}
			}
			return bitmap;
		}
		
		

	}
	

}

适配器的思路是这样的:

一:GridView要滑动,所以我们让它实现了OnScrollListener监听器,并实现了监听器的两个方法

1.public void onScrollStateChanged(AbsListView view, int scrollState)

这个方法用于处理屏幕滑动时的事件,在这里我们限定了,当屏幕静止时才开启加载图片的任务,滑动时则停止任务

2.public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,  int totalItemCount)

这个方法用于处理刚进入程序时的事件,在这里我们限定了第一次进入程序时要开启加载图片任务,不然会不显示图片

二:进入加图片的任务后,首先从缓存区通过键查找缓存区是否有该键值对应的图片,如果有的话,直接把该Bitmap对象赋给imageView的实例,如果缓存区没有,则把url传入,开启下载任务。

三:下载任务中使用异步任务,在doinBackgroud中去下载图片,如果下载成功,则首先把图片加入缓存区,然后把Bitmap对象返回到onPostExecute()中去更新UI,设置imageView。


具体每一步的逻辑在代码中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值