网路下载图片,并以滚动列表的方式展示图片资源,是一种典型的Android App开发场景,但是如何更好的去实现这种效果一直是Android程序员所头疼的事情。比如,将下载的图片数据存储到本地,那就会造成一个原声Android代码的卡顿(IO流的操作会造成裂变滚动的卡顿)。如果将他们存储在网络断,那程序员又必须去关心何时要取消请求队列中的请求,如何将下载的图片数据在内存中做高效的缓存,以及一系列的问题。

偏偏在这时,谷歌I/O大会上介绍了两个有意思的图片加载库:Volley和Picasso。 其实本质上这两个库的功能并不是一样的,但是它们都提供了解决图片加载问题的方案。我决定将她俩都部署到我的项目当中PhotoGallery,并看看她俩各自优势。

PhotoGallery是一个Flickr的前端应用,显示最新的Flickr图片,先看下PhotoGallery的截图:

如果继续往下拉,会看到更多的图片,接下来让我们关注在图片加载问题上。

在PhotoGalleryFragment碎片中,有一个叫做ThumbnailDownloader的组件,它是一个单线程,专门用来负责下载图片,并且提供了一个回调接口用来通知下载完成。

ThumbnailDownloader在Activity的onCreate方法中进行初始化,主要分三步:

1、设置回调监听

2、启动线程

3、启动循环,保证请求队列已经准备好接受一个一个的图片加载请求

具体代码参考如下:

 @Overridepublic 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方法时,过时的请求需要被清空掉:

@Overridepublic void onDestroyView() {super.onDestroyView();mThumbnailThread.clearQueue();}

然后在onDestroy方法中,整个线程需要停止:

@Overridepublic 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);}@Overridepublic 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);}@Overridepublic 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其实并不是一个图片的加载库--它是一个轻量的网络请求库,核心部分就是处理网络请求并缓存请求结果。简单使用如下代码所示:

@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mQueue = Volley.newRequestQueue(getActivity());GalleryItemRequest itemsRequest = GalleryItemRequest.newRecentItemsRequest(null, new Listener<ArrayList<GalleryItem>>() {@Overridepublic void onResponse(ArrayList<GalleryItem> items) {mItems = items;setupAdapter();}});itemsRequest.setTag(this);mQueue.add(itemsRequest);}@Overridepublic void onDestroy() {super.onDestroy();mQueue.cancelAll(this);}

GalleryItemRequest是一个自定义的网络请求解析类,用于将请求返回的xml数据填充到一个model类中。

接下来看一下使用Volley如何进行图片的加载:

@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);...mQueue = Volley.newRequestQueue(getActivity());mImageLoader = new ImageLoader(mQueue, new ImageCache() {@Overridepublic void putBitmap(String key, Bitmap value) { }@Overridepublic 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);}@Overridepublic 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;}}

原生代码加载网络图片和Volley和Picasso的简单介绍和优缺点对比相关推荐

  1. 【转载】一行代码加载网络图片到ImageView——Android Picasso

    原文链接:一句代码加载网络图片到ImageView--Android Picasso  注意:此处使用下面代码需要先配置一下gradle,下载所需包. 具体操作如下图: compile 'com.sq ...

  2. Google官方网络框架-Volley的使用解析Json以及加载网络图片方法

    Google官方网络框架-Volley的使用解析Json以及加载网络图片方法 Volley是什么?Google I/O 大会上,Google 推出 Volley的一个网络框架Volley适合什么场景? ...

  3. Android Volley完全解析2:使用Volley加载网络图片

    原文链接:http://blog.csdn.net/guolin_blog/article/details/17482165,CSDN 郭霖 在上一篇文章中,我们了解了Volley到底是什么,以及它的 ...

  4. Android Volley完全解析(二),使用Volley加载网络图片 转载:http://blog.csdn.net/guolin_blog/article/details/174

    转载:http://blog.csdn.net/guolin_blog/article/details/17482165 在上一篇文章中,我们了解了Volley到底是什么,以及它的基本用法.本篇文章中 ...

  5. Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide开源组件加载网络图片的优缺点比较...

    在android中的加载网络图片是一件十分令人头疼的事情,在网上有着许多关于加载网络图片的开源库,可以让我们十分方便的加载网络图片.在这里我主要介绍一下我自己在使用Volley, Picasso, U ...

  6. AFNetworking 之加载网络图片

    AFNetworking 之加载网络图片 我们平常用AF来进行网络请求,其实AF也可以作为轻量级的应用来请求网络图片哦.那么我们考虑一下AF是如何设计请求网络图片框架的呢? 1.入口 封装的时候从UI ...

  7. Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较

    在android中的加载网络图片是一件十分令人头疼的事情,在网上有着许多关于加载网络图片的开源库,可以让我们十分方便的加载网络图片.在这里我主要介绍一下我自己在使用Volley, Picasso, U ...

  8. android studio 加载图片,Android Studio 加载网络图片

    Android Studio是基于gradle的一个Android开发软件,在引用网络图片的时候需要连接第三方库,这里介绍 引用glide的方法. 一.在github页面搜索glide,点击第一个 二 ...

  9. iOS原生如何加载HTML中img标签的图片

    原文出自:iOS原生如何加载HTML中img标签的图片 前言 最近iOS App项目中使用Webview加载H5页面比较多,也有不少朋友经常问到这个问题,在这里我也学习学习如何通过iOS原生的方式来加 ...

最新文章

  1. sql server agent会自动关闭_车用自动灭火器(装置)国内超细干粉自动灭火装置技术对比_搜狐汽车...
  2. 1-Dimensional Heightfield Visibility Query
  3. 计算机usb2.0失效,Win10电脑USB2.0-CRW没有驱动程序的解决方法
  4. 【牛客 - 551C】CSL 的密码(后缀数组,后缀自动机,随机算法)
  5. Python制作彩色验证码
  6. UVa 1585 - Score
  7. Ant十五大最佳实践
  8. OpenGL中的坐标变换、矩阵变换【转载】
  9. 简述er图的作用_用例图、ER图、功能结构图
  10. 百度竞价关键词选词技巧
  11. 小米机顶盒安装第三方软件流程
  12. java 图片缩放 失真_Java图片缩小后不失真的代码(缩略图)
  13. 对角化求可逆矩阵_「线性代数」求可逆矩阵P,使得相似矩阵对角化
  14. word怎么在下一页添加表头_word表格在换页时能否自动在新换页上带上表头,如何设置...
  15. 吞吐量和IOPS测试
  16. 老板彻底晕菜!美女是这样要求加工资
  17. Excel之UPPER、LOWER、IFERROR和SUBSTITUTE函数
  18. 漫步有感 | 让自己温和一点
  19. 【学习笔记】AD智能PDF导出(装配文件)
  20. 根据菜鸟教程自学html的目录

热门文章

  1. 快递与电商的恩怨纠纷
  2. 一行命令统计出多个文件夹中的多种类型的代码行数
  3. C#数据结构(4) 稀疏矩阵与稀疏方阵
  4. 机房收费系统(VB.NET)——超详细的报表制作过程
  5. 未来,什么样的程序员才是不可替代的?
  6. java显示日历 插件_JavaWeb项目FullCalendar日历插件使用的示例代码
  7. vscode terminal主题配色
  8. html中常用的标签小结
  9. c语言实现矩阵行初等变换
  10. 【社区周会】2021-05-11 内容概要