基于RecyclerView和Volley的瀑布流照片墙实现
2015-12-30 20:40
585 查看
博主最近在学习Volley框架,便想写个Demo练练手,于是这个基于RecyclerView和Volley的瀑布流照片墙应运而生= =。话不多说进入正题~
记得添加Gradle的dependencies,并且导入volley作为Lib。具体可以参考:http://blog.csdn.net/u010940300/article/details/44309405
RecyclerView的基本用法请参考:http://frank-zhu.github.io/android/2015/01/16/android-recyclerview-part-1/以及官方文档。
由于使用volley框架不能在获取图片之前获取具体的图片大小,因此在初始化时博主将一部分图片集体载入,之后在该部分图片全部加载完成之后再调用notifyDataSetChanged()更新RecyclerView。具体代码如下:
下面是效果图:
![](http://img.blog.csdn.net/20151231111840613?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20151231142930974?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
感觉和郭神的一样,我可没有盗图= =。只是我用的他DEMO中的图片地址。
下面附上DEMO地址:https://github.com/xiehaochn/WaterfallDemo
恭迎各路大神指正
记得添加Gradle的dependencies,并且导入volley作为Lib。具体可以参考:http://blog.csdn.net/u010940300/article/details/44309405
RecyclerView的基本用法请参考:http://frank-zhu.github.io/android/2015/01/16/android-recyclerview-part-1/以及官方文档。
由于使用volley框架不能在获取图片之前获取具体的图片大小,因此在初始化时博主将一部分图片集体载入,之后在该部分图片全部加载完成之后再调用notifyDataSetChanged()更新RecyclerView。具体代码如下:
private void refreshLraCache(final int refreshNum) { //加载状态设置为未完成 Log.d("WaterFall","refresh start"); allLoaded=false; progressBar.setVisibility(View.VISIBLE); if(refreshNum==0){ allLoaded=true; progressBar.setVisibility(View.GONE); } for(int i=itemCount;i<itemCount+refreshNum;i++){ final int finalI = i; requestqueue.add(new ImageRequest(ImageURLs.imageUrls[i], new Response.Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { //将返回的Bitmap加入内存缓存 cache.put(ImageURLs.imageUrls[finalI],response); ImageSize imageSize=new ImageSize(response.getWidth(),response.getHeight()); sizeHashMap.put(ImageURLs.imageUrls[finalI],imageSize); //所有任务完成后将缓存传入Adapter并更新视图 taskCount++; progress= (int) ((float)taskCount/(refreshNum-1)*100); progressBar.setProgress(progress); if(taskCount==refreshNum) { adapter.setLruCache(cache); adapter.setSizeHashMap(sizeHashMap); //更新元素个数 itemCount=itemCount+refreshNum; adapter.setItemCount(itemCount); adapter.notifyDataSetChanged(); progressBar.setVisibility(View.GONE); progress=0; taskCount=0; //加载状态设置为全部完成 allLoaded=true; Log.d("WaterFall","refresh end"); } Log.d("WaterFall","Task: "+finalI+" completed"); Log.d("WaterFall","remaining memorysize is "+(cacheSize-cache.size())); } },spanWidth,0, ImageView.ScaleType.CENTER_CROP,null,null)); }在触底加载更多时,依然调用该方法加载之后的图片。在图片加载之后,将Bitmap存入之前初始化的LruCache中,并将图片的大小信息封装为ImageSize类存入一个HashMap。当该部分所有图片加载完成时(即taskCount==refreshNum)将LruCache、itemCount、sizeHashMap传入adapter并调用notifyDataSetChanged()刷新,并将加载状态设置为完成(将用于触底加载的判断,当未完成加载时不会再次调用refreshCache()方法)。
private void setLruCache() { //获取最大缓存大小,单位M int maxCacheSize= (int) (Runtime.getRuntime().maxMemory()/1024); cacheSize=maxCacheSize/8; cache=new LruCache<String,Bitmap>(cacheSize){ @Override protected int sizeOf(String key, Bitmap value) { //重写LruCache中计算元素大小方法 return value.getByteCount()/1024; } }; }
public class ImageSize { private int imageWidth; private int imageHeight; public ImageSize(int imageWidth,int imageHeight){ this.imageWidth=imageWidth; this.imageHeight=imageHeight; } public int getImageWidth(){ return imageWidth; } public int getImageHeight(){ return imageHeight; } }在adapter的onBindViewHolder()中,首先判断内存缓存是否存在。若存在直接显示图片,若不存在则先尝试获取图片尺寸并设置占位图片,然后再次发送volley请求下载图片。
@Override public void onBindViewHolder(final WaterFallVH holder, int position) { if(lruCache.get(ImageURLs.imageUrls[position])!=null){ //内存缓存存在直接加载 holder.imageView.setImageBitmap(lruCache.get(ImageURLs.imageUrls[position])); }else{ //若尺寸信息缓存存在,则获取图片大小信息 if(sizeHashMap.get(ImageURLs.imageUrls[position])!=null) { int[] size = getLruSize(position); Bitmap bitmap=resizedImage(BitmapFactory.decodeResource(context.getResources(), R.drawable.loading),size[0],size[1]); //加载占位图片 holder.imageView.setImageBitmap(bitmap); } //内存缓存中不存在该元素,发送Volley请求 sendVolleyRequest(holder,position); }最后通过重写OnScrollListener中的onScrollStateChanged()方法判断是否触底以及是否开始加载更多图片。首先判断是否停止滑动,之后判断当前的加载任务是否完成,随后获取每列的最后一个可见View的位置编号,比较之后获得最大的视图编号。若编号与adapter当前的总元素个数相同,则判断已经滑动到最底部,最后判断待加载图片个数是否大于10来决定传入refreshLruCache()中的参数。当剩余图片不足10时,更新图片之后将标志位noMore设置为true,若再触底将不再调用refreshLruCache()并提示没有更多图片。
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); //判断是否停止滚动 if(newState==RecyclerView.SCROLL_STATE_IDLE) { //判断当前加载是否完成 if (allLoaded == true) { //得到每一列最后一个可见的元素的Position int[] lastvisibalItem = layoutManager.findLastVisibleItemPositions(null); int lastposition = 0; if (columsCount != 1) { lastposition = Math.max(lastvisibalItem[0], lastvisibalItem[1]); for (int i = 2; i < columsCount; i++) { //获取整个视图可见元素中Position的最大值 lastposition = Math.max(lastposition, lastvisibalItem[i]); } } else { lastposition = lastvisibalItem[0]; } if ((lastposition + 1) == itemCount) { //当最后一个可见元素的Position与加载的元素总数相等时,判断滑到底部,更新缓存、加载更多 if ((lastposition + 11) <= ImageURLs.imageUrls.length) { //当还剩余十个以上元素待加载时,加载10个元素 refreshLraCache(refreshSize); Toast.makeText(context, "Loading...", Toast.LENGTH_SHORT).show(); } else { if(!noMore) { //当剩余元素不足十个时,加载剩余元素并提示 int remaining = ImageURLs.imageUrls.length - lastposition - 1; refreshLraCache(remaining); Toast.makeText(context, "Loading...", Toast.LENGTH_SHORT).show(); //没有更多图片 noMore = true; }else { //没有更多图片时提示 Toast.makeText(context, "No more pictrues", Toast.LENGTH_SHORT).show(); } } } } }大概思路就是这样了。什么?你说只有内存缓存太low了。其实volley自带diskCache,不过默认的大小只有5M,还没有内存缓存大= =。不过volley的强大之处就在于其高度的扩展性,于是博主修改了一下volley默认初始化RequestQueue类所传入的diskCache,将其改为了50M。
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir,diskCacheSize), network);就这么一句就解决了,不得不服啊~volley的设计模式真的十分强大。想要了解更多:http://a.codekk.com/blogs/detail/54cfab086c4761e5001b2542
下面是效果图:
感觉和郭神的一样,我可没有盗图= =。只是我用的他DEMO中的图片地址。
下面附上DEMO地址:https://github.com/xiehaochn/WaterfallDemo
恭迎各路大神指正
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/wronged.gif)
相关文章推荐
- 状态模式
- C#与.NET程序员面试宝典 Day2
- 记一次驴唇不对马嘴的DIY之旅(五)
- 吾之简单的KMP算法学习,字符串操作基本功
- 记住,web项目一定要看console提示的信息
- iOS 编码的一些规范
- swift-观察者模式
- Windows中Qt+OpenCV配置
- 装饰模式
- 防止sql注入和sqlmap介绍
- ubuntun下的Nvidia显卡安装
- C++-类的理解
- PE文件格式
- java基础知识总结
- Intel大战高通、三星:结果瞠目结舌!
- 18-6
- 【splay】BZOJ 1152 && 3506:[cqoi2014]排序机械臂
- Servlet基础
- Plugin execution not covered by lifecycle configuration...
- jedis连接sentinel示例程序