Volley该框架使用了大量的请求图片
尊重原创 http://write.blog.csdn.net/postedit/26142025
代码下载:http://download.csdn.net/detail/yuanzeyao2008/7363999
假设你希望了解Volley框架的原理,欢迎阅读
前面已经说过,Volley框架能够用来请求String,XML,Json,Image以及一些自己定义的类型,这篇文章主要解说使用Volley请求大量图片。并使用GridView展示出来。这个功能在非常多应用中都会用到,如PPS等类型的播放器,淘宝等等。
像这类应用无非就是要解决一下问题:
1、避免OOM,在使用GridView等控件显示大量图片时,假设对缓存处理不当,是很easy出现OOM的。
2、GridView错位显示,比方GridView中的某个ImageView等待某一个图片(没有返回)。然而你此时又滑动了GridView,那么此时的GridView中的ImageView须要的是另外一张图片,假设你之前的图片已经返回回来是不能显示出来的。
把这两个问题攻克了,此类问题也就差点儿相同了,剩下的就是效率问题了,这点Volley已经处理好了,我们须要处理的就是以上两点
1、解决OOM
我就顺便讲解说决OOM的经常使用策略吧
OOM出现的情况可能是显示的图片非常大可是数量不是非常多。也有可能是显示的图片非常多可是图片不是非常大,我们先看第一种情况
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
我们直接看官网怎么处理这个问题。我翻译了一下
对于某些图片。分辨率往往比我们须要的高,比方我们使用Galley控件展示我们使用手机拍摄的照片时,这些照片的分辨率都比我们的屏幕分辨率高,所以在显示的时候我们应该减少这些图片的分辨率,由于此时高分辨率的图片在视觉上不会给我们带来不论什么区别。反而会占用我们移动设备的珍贵内存。以下我们就学习怎样将高分辨率的图片减少它的分辨率
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
我们在使用BitmapFactory读取图片数据的时候,假设我们把options.inJustDecodeBounds设置为true,那么BitmapFactory仅仅会读取图片的高度和宽度等信息。不会将图片数据读入内存
options另一个属性options.inSampleSize,BitmapFactory在解析图片数据的时候,会将图片的宽度和高度变为原来的1/inSampleSize,这样图片大大小就会变为1/(inSampleSize*inSampleSize),比方inSampleSize=2 那么图片大小会变为原来的1/4
那么inSampleSize这个值怎么获取呢。通过下面算法就可以
/**
optiosns 就是上面我得到的options
reqWidth 就是我们须要图片的宽度
reqHeight 就是我们须要图片的高度
*/
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2;
final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
} return inSampleSize;
}
解析图片至须要的宽度和高度
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
//首先将这个值设置为true, 所以仅仅会获取高度和宽度
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options); // 依据须要的宽度和高度 图片的实际高度和宽度 计算缩小比例
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 然后将该值设置为false,真正解析图片
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
通过以上的步骤遍能够将图片缩小至某一大小,从而避免OOM
再来讲讲另外一种OOM,这样的OOM是由于有太多的图片,所以解决方式就是使用内存缓存和磁盘缓存
在Andorid中有两个类
LruCache和DiskLruCache这个两个类分别相应内存缓存和磁盘缓存
详细使用见
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
到此为止OOM的问题就攻克了。以下看看错位问题
方案一:
对于每个请求的URL就设置到ImageView的tag中如imageView.setTag(url).当某一个请求成功返回一张图片时,推断ImageView的tag是否是当前请求的url
假设是的。那么就显示出来。并增加缓存。假设不是的,那么只增加缓存
方案二:
一旦GridView滑动。那么取消全部的请求,当GridView停止时。里面開始请求能够看见的ImageView须要的图片,今天的样例我就是使用另外一种方案,须要设置OnScrollListener
好了 我们如今開始写代码吧
先总结一下Volley框架的使用步骤吧
(1) 初始化RequestQueue
(2) 创建自己的Request
(3) 将Request增加到RequestQueue中。
可是对于图片的请求步骤略微有点不同,图片的请求涉及到ImageLoader实现的,事实上ImageLoader也是通过以上三步实现图片请求的
以下我就在Appliaction中初始化Volley使用的环境吧
public class VolleyApplication extends Application
{
private static final String TAG = "VolleyApplication";
//请求队列
private RequestQueue mRequestQueue;
private static VolleyApplication instance;
//用于图片请求
private ImageLoader mImageLoader;
//使用单例模式
public static VolleyApplication getInstance()
{
return instance;
} public RequestQueue getRequestQueue()
{
return mRequestQueue;
} public ImageLoader getImageLoader()
{
return mImageLoader;
}
@Override
public void onCreate()
{
super.onCreate();
//初始化内存缓存文件夹
File cacheDir = new File(this.getCacheDir(), "volley");
/**
初始化RequestQueue,事实上这里你能够使用Volley.newRequestQueue来创建一个RequestQueue,直接使用构造函数能够定制我们须要的RequestQueue,比方线程池的大小等等
*/
mRequestQueue=new RequestQueue(new DiskBasedCache(cacheDir), new BasicNetwork(new HurlStack()), 3); instance=this; //初始化图片内存缓存
MemoryCache mCache=new MemoryCache();
//初始化ImageLoader
mImageLoader =new ImageLoader(mRequestQueue,mCache);
//假设调用Volley.newRequestQueue,那么以下这句能够不用调用
mRequestQueue.start();
}
}
使用LrcCache实现的一个图片缓存,这个基本上能够通用
public class MemoryCache implements ImageCache
{
private static final String TAG = "MemoryCache";
private LruCache<String, Bitmap> mCache; public MemoryCache()
{
//这个取单个应用最大使用内存的1/8
int maxSize=(int)Runtime.getRuntime().maxMemory()/8;
mCache=new LruCache<String, Bitmap>(maxSize){
@Override
protected int sizeOf(String key, Bitmap value) {
//这种方法一定要重写,不然缓存没有效果
return value.getHeight()*value.getRowBytes();
}
};
} @Override
public Bitmap getBitmap(String key) {
return mCache.get(key);
} @Override
public void putBitmap(String key, Bitmap value) {
mCache.put(key, value);
}
}
那么開始写代码吧
(1) 首先给出Activity的布局吧
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<GridView
android:id="@+id/grid_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnWidth="128dip"
android:stretchMode="columnWidth"
android:numColumns="2"
android:verticalSpacing="1dip"
android:horizontalSpacing="1dip"
android:gravity="center"
></GridView>
</LinearLayout>
(2) 然后每一个Item的布局
<? xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content" > <ImageView
android:id="@+id/photo"
android:layout_width="128dip"
android:layout_height="128dip"
android:src="@drawable/empty_photo"
android:layout_centerInParent="true"
/> </RelativeLayout>
(3) Activity代码
public class ImageActivity extends Activity
{
private static final String TAG = "ImageActivity";
private GridView mGridView;
private ImageAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.imagelayout);
initViews();
} private void initViews()
{
Log.i(TAG,"initViews");
mGridView=(GridView)this.findViewById(R.id.grid_image);
adapter=new ImageAdapter(this,mGridView);
mGridView.setAdapter(adapter); }
}
(4) 最重要部分代码
public class ImageAdapter extends BaseAdapter implements OnScrollListener
{
private static final String TAG = "ImageAdapter";
private Context context;
private String[] items=Images.imageThumbUrls;
private GridView mGridView; /**
* 标识是否是第一次运行,假设是第一次运行 onScrollStateChanged是不调用的
*/
private boolean isFirstEnter;
/**
* 第一个能够看见的item
*/
private int firstSeeItem; /**
* 记录上一次能够看见的第一个,由于假设已经到顶部。向下滑动GridView也会运行onScrollStateChanged 所以第一个能够见的没有变化,那么就不运行
*/
private int orifirstItem;
/**
* 能够看见item的总数
*/
private int totalSeeItem; public ImageAdapter(Context context,GridView mGridView)
{
this.context=context;
this.mGridView=mGridView;
//注冊这个是为了在滑动的时候停止下载图片,不然非常卡
mGridView.setOnScrollListener(this);
isFirstEnter=true;
} @Override
public int getCount() {
return items.length;
} @Override
public Object getItem(int position) {
return items[position];
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.v(TAG, "imagedown--->getView");
ImageView imgView=null;
if(convertView==null)
{
convertView=LayoutInflater.from(context).inflate(R.layout.imageitems, null);
}
imgView=(ImageView)convertView.findViewById(R.id.photo);
imgView.setImageResource(R.drawable.empty_photo);
//通过GridView的findViewByTag方法找到该View,防止错位发生
imgView.setTag(items[position]); return convertView;
} @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
Log.v(TAG, "imagedown--->onScroll");
firstSeeItem=firstVisibleItem;
totalSeeItem=visibleItemCount; if(isFirstEnter && visibleItemCount>0)
{
orifirstItem=firstVisibleItem;
startLoadImages(firstSeeItem,totalSeeItem);
isFirstEnter=false;
}
} @Override
public void onScrollStateChanged(AbsListView view, int scrollState)
{
Log.v(TAG, "imagedown--->onScrollStateChanged");
if(orifirstItem!=firstSeeItem)
{
if(scrollState==SCROLL_STATE_IDLE)
{
startLoadImages(firstSeeItem,totalSeeItem);
orifirstItem=firstSeeItem;
}else
{
ImageUtils.cancelAllImageRequests();
}
} }
/**
開始下载图片
first就是第一个能够看见的position
total就是能够看见个Item个数
*/
private void startLoadImages(int first,int total)
{
Log.v(TAG, "imagedown--->startLoadImages,first-->"+first+",total-->"+total);
for(int i=first;i<first+total;i++)
{
ImageUtils.loadImage(items[i], mGridView);
}
}
}
(5) 请求图片工具类
public class ImageUtils
{
private static final String TAG = "ImageUtils"; public static void loadImage(final String url,final GridView mGridView)
{ ImageLoader imageLoader=VolleyApplication.getInstance().getImageLoader();
ImageListener listener=new ImageListener() {
ImageView tmpImg=(ImageView)mGridView.findViewWithTag(url);
@Override
public void onErrorResponse(VolleyError arg0) {
//假设出错。则说明都不显示(简单处理),最好准备一张出错图片
tmpImg.setImageBitmap(null);
} @Override
public void onResponse(ImageContainer container, boolean arg1) { if(container!=null)
{
tmpImg=(ImageView)mGridView.findViewWithTag(url);
if(tmpImg!=null)
{
if(container.getBitmap()==null)
{
tmpImg.setImageResource(R.drawable.empty_photo);
}else
{
tmpImg.setImageBitmap(container.getBitmap());
}
}
}
}
};
ImageContainer newContainer=imageLoader.get(url, listener,128,128);
} /**
* 取消图片请求
*/
public static void cancelAllImageRequests() {
ImageLoader imageLoader = VolleyApplication.getInstance().getImageLoader();
RequestQueue requestQueue = VolleyApplication.getInstance().getRequestQueue();
if(imageLoader != null && requestQueue!=null){
int num = requestQueue.getSequenceNumber();
//这种方法是我自己写的,Volley里面是没有的。所以仅仅能使用我给的Volley.jar才有这个函数
imageLoader.drain(num);
}
} }
好了 今天就写到这里吧,有什么问题欢迎留言讨论。代码在前面已经提供下载了。。
。
版权声明:本文博客原创文章。博客,未经同意,不得转载。
Volley该框架使用了大量的请求图片的更多相关文章
- Android 学习笔记之Volley开源框架解析(一)
PS:看完了LGD的六场比赛...让人心酸... 学习内容: 1.Http请求的过程... 2.Volley的简单介绍... 1.Http请求... 这里只是简单的说一下Http请求的过程.. ...
- 谷歌Volley网络框架讲解——BasicNetwork类
谷歌Volley网络框架讲解——BasicNetwork类 这个类是toolbox工具箱包里的,实现了Network接口. 先来看下Network这个interface,performRequest( ...
- Volley网络框架完全解析(缓存篇)
在上一篇中讲完了Volley框架怎么使用,那么这篇就来讲讲Volley框架的缓存机制 我们看Volley内部源码发现: Volley框架内部自己处理了DiskBasedCache硬盘缓存,但是没有处理 ...
- Android-Volley网络通信框架(自己定义Request 请求:实现 GsonRequest)
1.回想 上篇学习了android 通过 volley 网络通信框架 实现 请求图片的三种方法! 2.重点 (1)复习和熟悉 StringRequest ,JsonObjectRequest 方法 ( ...
- Android开发之Volley网络通信框架
今天用了一下Volley网络通信框架,感觉挺好用的,写个博客记录一下用法.方便以后VC. Volley(Google提供的网络通信库,能使网络通信更快,更简单,更健壮.) 功能模块: 1. JSON, ...
- 【Spring学习笔记-MVC-5】利用spring MVC框架,实现ajax异步请求以及json数据的返回
作者:ssslinppp 时间:2015年5月26日 15:32:51 1. 摘要 本文讲解如何利用spring MVC框架,实现ajax异步请求以及json数据的返回. Spring MV ...
- 第三百一十五节,Django框架,CSRF跨站请求伪造
第三百一十五节,Django框架,CSRF跨站请求伪造 全局CSRF 如果要启用防止CSRF跨站请求伪造,就需要在中间件开启CSRF #中间件 MIDDLEWARE = [ 'django.midd ...
- robotframework - 框架做接口自动化post请求
1.做get请求之前先安装 Request库,参考github上链接 :https://github.com/bulkan/robotframework-requests/#readme 2.请求&a ...
- scrapy框架的日志等级和请求传参, 优化效率
目录 scrapy框架的日志等级和请求传参, 优化效率 Scrapy的日志等级 请求传参 如何提高scripy的爬取效率 scrapy框架的日志等级和请求传参, 优化效率 Scrapy的日志等级 在使 ...
随机推荐
- Jenkins快速搭建持续集成
基于Jenkins快速搭建持续集成环境 Jenkins+tortoisesvn+MSBuild做到持续集成 附Jenkins的使用:http://www.infoq.com/cn/articles/M ...
- 看到关于socket非阻塞模式设置方式记录一下。
关于socket的阻塞与非阻塞模式以及它们之间的优缺点,这已经没什么可言的:我打个很简单的比方,如果你调用socket send函数时: 如果是阻塞模式下: send先比较待发送数据的长度len和套接 ...
- 全方位深度剖析--性能测试之LoardRunner 介绍
一.介绍 LoardRunner是一种预测系统行为和性能负载的测试工具.通过模拟上千万用户实施并发负载及实时性能监控的方式来确认和查找系统的瓶颈,LoardRunner能够对整个企业架构进行测试.通过 ...
- html5的自定义data-*属性和jquery的data()方法的使用
人们总喜欢往HTML标签上添加自定义属性来存储和操作数据.但这样做的问题是,你不知道将来会不会有其它脚本把你的自定义属性给重置掉,此外,你这样做也会导致html语法上不符合Html规范,以及一些其它副 ...
- 树莓派的.bashrc和.bash_aliases文件
在你的home文件夹中,你能够找到一个包括用户配置的隐藏文件.bashrc. 你能够依据自己的须要改动这个文件. 文件里为你提供了一些实用的调整设置.默认情况下当中一些设置是被凝视掉的. 比如,一些l ...
- EXT2/EXT3文件系统(一)
整理自<鸟哥的Linux私房菜>,整理者:华科小涛http://www.cnblogs.com/hust-ghtao/ 1.文件系统概念引入 文件系统是一种存储和组织计算机数据的方法,它使 ...
- Net基础恶补
一 自定义事件 1 之前一直都是使用事件调用来触发事件,看代码 // 定义一个事件 public event EventHandler; //触发事件 public void OnEvent(){ i ...
- WITH+HInt MATERIALIZE 不见得有效
那个要多次调用才需要物化的. 只调用一次,物化没用 MATERIALIZE 语法:MATERIALIZE 描述:指示优化器将内联视图实体化————执行过程中会创建基于视图的临时表. with dd ...
- struts2官方演示程序总结struts2-blank
struts-2.2.3.1-all\struts-2.2.3.1\apps\struts2-blank总结 1.Html可以访问action ,如下: < head > ...
- oracle 之数据字典屣履造门。
oracle 之数据字典屣履造门.(更新中) 今天是2013-06-20,哎,写这篇笔记的时候,我发现我是一个非常懒惰的人,这篇文章本该昨天就完成的,想起了钱鹤滩的<明日歌> ...