原生代码加载网络图片和Volley和Picasso的简单介绍和优缺点对比
2016-03-25 10:23
627 查看
网路下载图片,并以滚动列表的方式展示图片资源,是一种典型的Android App开发场景,但是如何更好的去实现这种效果一直是Android程序员所头疼的事情。比如,将下载的图片数据存储到本地,那就会造成一个原声Android代码的卡顿(IO流的操作会造成裂变滚动的卡顿)。如果将他们存储在网络断,那程序员又必须去关心何时要取消请求队列中的请求,如何将下载的图片数据在内存中做高效的缓存,以及一系列的问题。
偏偏在这时,谷歌I/O大会上介绍了两个有意思的图片加载库:Volley和Picasso。 其实本质上这两个库的功能并不是一样的,但是它们都提供了解决图片加载问题的方案。我决定将她俩都部署到我的项目当中PhotoGallery,并看看她俩各自优势。
PhotoGallery是一个Flickr的前端应用,显示最新的Flickr图片,先看下PhotoGallery的截图:
![](http://img.blog.csdn.net/20160325090901827?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
如果继续往下拉,会看到更多的图片,接下来让我们关注在图片加载问题上。
在PhotoGalleryFragment碎片中,有一个叫做ThumbnailDownloader的组件,它是一个单线程,专门用来负责下载图片,并且提供了一个回调接口用来通知下载完成。
ThumbnailDownloader在Activity的onCreate方法中进行初始化,主要分三步:
1、设置回调监听
2、启动线程
3、启动循环,保证请求队列已经准备好接受一个一个的图片加载请求
具体代码参考如下:
这里的listener就是负责当图片下载完毕之后,将其设置到ImageView控件之上
当调用onDestroyView方法时,过时的请求需要被清空掉:
然后在onDestroy方法中,整个线程需要停止:
在PhotoGallery的适配器中,先给ImageView设置一个默认的本地图片,然后调用ThumbnailDownloader的queueThumbnail方法,向队列中添加图片加载请求:
Okay! 到这里原生的写法差不多已经完成了,ThumbnailDownloader是一个非常简单的图片加载组件,它按照请求被添加进队列的次序,依次的下载每一张图片。如果请求已经过时,则会忽略此请求而直接跳转到下一个请求。这种原生的实现有如下几个优点:简单,体积小,容易理解。
但是它也有它的缺陷:
我不得不在多个碎片的生命周期方法中做聚合的工作,比如:我必须在分3步来对ThumbnailDownloader做初始化,需要手动的清空过时的请求,当碎片结束后需要将线程停止掉。以上问题可以通过一个单例的模式来解决,但是如果使用单例,问题就会接踵而来:当有多个碎片都需要下载图片时,我的APP需要可以解决多个碎片请求的同步问题,这样就会将问题搞得更严重,通俗来讲,也就是解一个B级Bug,引出3个A级Bug。 OMG!!
妈蛋!我受够了,喝杯果汁先。
先品尝下Picasso, 感觉如丝般顺滑
Picasso这个框架是由国外的一家叫Square的公司所研发的。在工程中导入这个也是非常的简单,只需在pom文件中添加几行配置,或者是下载相应jar包之后在eclipse中导入即可。Squqre声称Picasso已经考虑并解决了图片加载的异步缓存等问题,具体的使用Picasso加载图片只需一行代码搞定,如下所示:
Square说的没有错,上面这行代码同我最终自己实现的组件非常类似。并且onCreate(),onDestroyView(),onDestroy()方法通通不需要!然后在适配器中只要做一下稍微的修改即可,如下所示:
以上就是使用Picasso的整个实现。其实Picasso还具备了指定图片的placeholder的功能,并且它似乎复写了ImageView缩放的功能代码,因此我都是自己写placeholder。另外Picasso在下载完图片进行展示的时候,会有一个渐现的效果。
总结一下,使用Picasso的好处是什么呢?
1、一个自动被创建的图片加载的单例
2、图片可以被自动的缓存在内存或者硬盘当中
3、请求可以随时取消
4、可以同时执行多个加载请求
但是Picasso也有两个问题让我头疼,对于ImageView的scaleType属性,在使用Picasso时,并不会生效。比如如下代码:
但是听说在最新版本中已经可以支持了。有待验证!
另外Picasso致命的问题就是不能加载大图片,虽然不能导致内存溢出问题,但是去不能正常下载图片并显示
接下来看一下Volley,Volley其实并不是一个图片的加载库--它是一个轻量的网络请求库,核心部分就是处理网络请求并缓存请求结果。简单使用如下代码所示:
GalleryItemRequest是一个自定义的网络请求解析类,用于将请求返回的xml数据填充到一个model类中。
接下来看一下使用Volley如何进行图片的加载:
注意:在一个实际App中,mQueue和mImageLoader一般是在Application中进行初始化,并在整个app中是以单例的形式存在。
然后是适配器中的代码:
偏偏在这时,谷歌I/O大会上介绍了两个有意思的图片加载库:Volley和Picasso。 其实本质上这两个库的功能并不是一样的,但是它们都提供了解决图片加载问题的方案。我决定将她俩都部署到我的项目当中PhotoGallery,并看看她俩各自优势。
PhotoGallery是一个Flickr的前端应用,显示最新的Flickr图片,先看下PhotoGallery的截图:
如果继续往下拉,会看到更多的图片,接下来让我们关注在图片加载问题上。
在PhotoGalleryFragment碎片中,有一个叫做ThumbnailDownloader的组件,它是一个单线程,专门用来负责下载图片,并且提供了一个回调接口用来通知下载完成。
ThumbnailDownloader在Activity的onCreate方法中进行初始化,主要分三步:
1、设置回调监听
2、启动线程
3、启动循环,保证请求队列已经准备好接受一个一个的图片加载请求
具体代码参考如下:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... mThumbnailThread = new ThumbnailDownloader<ImageView>(new Handler()); mThumbnailThread.setListener(new ThumbnailDownloader.Listener<ImageView>() { public void onThumbnailDownloaded(ImageView imageView, Bitmap thumbnail) { if (isVisible()) { imageView.setImageBitmap(thumbnail); } } }); mThumbnailThread.start(); mThumbnailThread.getLooper(); }
这里的listener就是负责当图片下载完毕之后,将其设置到ImageView控件之上
当调用onDestroyView方法时,过时的请求需要被清空掉:
@Override public void onDestroyView() { super.onDestroyView(); mThumbnailThread.clearQueue(); }
然后在onDestroy方法中,整个线程需要停止:
@Override public void onDestroy() { super.onDestroy(); mThumbnailThread.quit(); }
在PhotoGallery的适配器中,先给ImageView设置一个默认的本地图片,然后调用ThumbnailDownloader的queueThumbnail方法,向队列中添加图片加载请求:
private class GalleryItemAdapter extends ArrayAdapter<GalleryItem> { public GalleryItemAdapter(ArrayList<GalleryItem> items) { super(getActivity(), 0, items); } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getActivity().getLayoutInflater() .inflate(R.layout.gallery_item, parent, false); } GalleryItem item = getItem(position); ImageView imageView = (ImageView)convertView .findViewById(R.id.gallery_item_imageView); imageView.setImageResource(R.drawable.brian_up_close); mThumbnailThread.queueThumbnail(imageView, item.getUrl()); return convertView; } }
Okay! 到这里原生的写法差不多已经完成了,ThumbnailDownloader是一个非常简单的图片加载组件,它按照请求被添加进队列的次序,依次的下载每一张图片。如果请求已经过时,则会忽略此请求而直接跳转到下一个请求。这种原生的实现有如下几个优点:简单,体积小,容易理解。
但是它也有它的缺陷:
我不得不在多个碎片的生命周期方法中做聚合的工作,比如:我必须在分3步来对ThumbnailDownloader做初始化,需要手动的清空过时的请求,当碎片结束后需要将线程停止掉。以上问题可以通过一个单例的模式来解决,但是如果使用单例,问题就会接踵而来:当有多个碎片都需要下载图片时,我的APP需要可以解决多个碎片请求的同步问题,这样就会将问题搞得更严重,通俗来讲,也就是解一个B级Bug,引出3个A级Bug。 OMG!!
妈蛋!我受够了,喝杯果汁先。
先品尝下Picasso, 感觉如丝般顺滑
Picasso这个框架是由国外的一家叫Square的公司所研发的。在工程中导入这个也是非常的简单,只需在pom文件中添加几行配置,或者是下载相应jar包之后在eclipse中导入即可。Squqre声称Picasso已经考虑并解决了图片加载的异步缓存等问题,具体的使用Picasso加载图片只需一行代码搞定,如下所示:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Square说的没有错,上面这行代码同我最终自己实现的组件非常类似。并且onCreate(),onDestroyView(),onDestroy()方法通通不需要!然后在适配器中只要做一下稍微的修改即可,如下所示:
private class GalleryItemAdapter extends ArrayAdapter<GalleryItem> { public GalleryItemAdapter(ArrayList<GalleryItem> items) { super(getActivity(), 0, items); } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getActivity().getLayoutInflater() .inflate(R.layout.gallery_item, parent, false); } GalleryItem item = getItem(position); ImageView imageView = (ImageView)convertView .findViewById(R.id.gallery_item_imageView); imageView.setImageResource(R.drawable.brian_up_close); Picasso.with(getActivity()) .load(item.getUrl()) .noFade() .into(imageView); return convertView; } }
以上就是使用Picasso的整个实现。其实Picasso还具备了指定图片的placeholder的功能,并且它似乎复写了ImageView缩放的功能代码,因此我都是自己写placeholder。另外Picasso在下载完图片进行展示的时候,会有一个渐现的效果。
总结一下,使用Picasso的好处是什么呢?
1、一个自动被创建的图片加载的单例
2、图片可以被自动的缓存在内存或者硬盘当中
3、请求可以随时取消
4、可以同时执行多个加载请求
但是Picasso也有两个问题让我头疼,对于ImageView的scaleType属性,在使用Picasso时,并不会生效。比如如下代码:
Picasso.with(getActivity()) .load(item.getUrl()) .placeholder(R.drawable.brian_up_close) .centerCrop() .noFade() .into(imageView);
但是听说在最新版本中已经可以支持了。有待验证!
另外Picasso致命的问题就是不能加载大图片,虽然不能导致内存溢出问题,但是去不能正常下载图片并显示
接下来看一下Volley,Volley其实并不是一个图片的加载库--它是一个轻量的网络请求库,核心部分就是处理网络请求并缓存请求结果。简单使用如下代码所示:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mQueue = Volley.newRequestQueue(getActivity()); GalleryItemRequest itemsRequest = GalleryItemRequest.newRecentItemsRequest(null, new Listener<ArrayList<GalleryItem>>() { @Override public void onResponse(ArrayList<GalleryItem> items) { mItems = items; setupAdapter(); } }); itemsRequest.setTag(this); mQueue.add(itemsRequest); } @Override public void onDestroy() { super.onDestroy(); mQueue.cancelAll(this); }
GalleryItemRequest是一个自定义的网络请求解析类,用于将请求返回的xml数据填充到一个model类中。
接下来看一下使用Volley如何进行图片的加载:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... mQueue = Volley.newRequestQueue(getActivity()); mImageLoader = new ImageLoader(mQueue, new ImageCache() { @Override public void putBitmap(String key, Bitmap value) { } @Override public Bitmap getBitmap(String key) { return null; } }); ... }
注意:在一个实际App中,mQueue和mImageLoader一般是在Application中进行初始化,并在整个app中是以单例的形式存在。
然后是适配器中的代码:
private class GalleryItemAdapter extends ArrayAdapter<GalleryItem> { public GalleryItemAdapter(ArrayList<GalleryItem> items) { super(getActivity(), 0, items); } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getActivity().getLayoutInflater() .inflate(R.layout.gallery_item_network, parent, false); } GalleryItem item = getItem(position); NetworkImageView imageView = (NetworkImageView)convertView .findViewById(R.id.gallery_item_imageView); imageView.setDefaultImageResId(R.drawable.brian_up_close); imageView.setImageUrl(item.getUrl(), mImageLoader); return convertView; } }
相关文章推荐
- The superclass "javax.servlet.http.HttpServlet" was not found on the Java
- Twsited异步网络框架
- Android中的HTTPS
- 图解SSL/TLS协议(HTTPS的安全层)
- The superclass "javax.servlet.http.HttpServlet" was not found on the Java
- 全站HTTPS能带来怎样的优势?HTTPS原理是什么、如何加密?
- HTTPS连接的前几毫秒发生了什么
- 解决URL中包含以及不包含https、www时引起的JS跨域问题
- HTTPS的层次结构和防范对象
- 启用全站HTTPS后不仅更安全而且更快 看淘宝是如何做到的????
- HTTPS和HTTP的区别
- 图解server端网络架构
- 使用C++ REST SDK开发简单的Web(HTTP)服务
- 流量劫持别抵制了,全站HTTPS是王道!
- 关于XMLHttpRequest对象的responseText属性
- tcp详解之三次握手和四次挥手
- idhttp.post方式 调用datasnap rest 远程方法
- HTTP in iOS你看我就够
- HttpURLConnection:POST和GET 网络请求
- http协议详解