Android应用开发中图片高效处理的研究

2015-05-30 13:59张延年米洪
智能计算机与应用 2015年6期

张延年 米洪

摘 要:一般在Android应用开发过程中都会涉及到图片处理的问题,包括图片的显示、下载、上传、压缩等方面,随着应用中要处理的图片数量的增加,如何快速而高效的对图片进行处理变得越来越重要。本文主要通过对几种比较成熟的图片处理开源框架的研究,结合实际项目案例详细阐述了图片高效处理的方法和步骤,同时对各处理方法的适用范围、优势以及注意事项进行了分析和说明。

关键词: Android应用开发;图片处理;开源框架

中图分类号:TP311 文献标识号:A 文章编号:2095-2163(2015)06-

Abstract: Android application development process in general will be related to the problem of image processing, including image display, download, upload, compression, etc.. Along with the increase in the number of images to deal with, how to deal with the image quickly and efficiently becomes more and more important. This paper mainly studies the open source framework of several more mature image processing, and combined with the actual project case, this paper expounds the methods and steps of the image processing. Based on the aboved, the paper also analyzes and explains the application scope, advantages and points of attention.

Key words:Android Application Development; Image Processing; Open Source Framework

0引 言

时下,在Android应用程序开发过程中对图片的处理问题呈现出高频的现实关注度,因此对其看站探索研究,势将具有重大应用价值。虽然一般的教科书上都会介绍图片处理的基本方法,但对于如何在实际项目开发中根据用户需求简捷、高效地实现图片处理功能这一重要内容却大都未予涉及。在早期的Android应用开发过程中常规的解决方案多是通过使用Android SDK提供的相关类库自定义相关方法,比如图片下载需要使用openConnection方法获取HttpURLConnection连接对象,然后使用getInputStream方法获取图片的输入流,再将输入流转换成Bitmap,最后借助Handler更新UI,显示下载的图片。这种解决方案虽然能实现项目的功能需求,但存在编码工作量大、代码无法复用、图片处理效率较低等问题,特别是对一些特定的应用场景(比如大图片处理、批量下载、断点续传等)将无法满足用户的客观高端需求。基于此,为解决以上问题出现了一些针对图片处理的开源框架,随着这些框架的日渐成熟,越来越多的开发者更倾向于借助开源框架来完成图片处理的功能。图片处理的内容包含很多方面,而其中网络传输过程的图片处理问题对程序的效率和性能影响堪称首要显著,因此本文重点讨论如何高效地实现网络传输过程中图片的下载、上传和压缩功能。

1图片下载

由于在Android应用中不能在UI线程中执行耗时操作[1],因此Android中图片的网络加载必须通过异步操作实施完成,也就是必须单独开启一个子线程来负责图片下载任务[2],当任务完成后将采用Handler机制通知UI线程更新界面。在ListView或GridView中加载图片的过程可做如下描述:首先尝试从内存缓存中获取,取到则返回,否则可试着从文件缓存中获取,取到则返回并更新到内存缓存,若仍落空则最后只能从网络上下载,由此而更新内存缓存和文件缓存 。评析上述过程可知,首先,实现这一指定功能至少要实现文件缓存类、内存缓存类、图片加载类,需要编写的代码相当多。其次,若要实现图片的高效、流畅下载还必须对代码进行全面优化[3]。第三,如果项目具有特殊的需求,比如超大图片或批量图片的下载,则需要考虑内存优化、图片压缩等更多方面的技术要求。基于以上考虑,下面将研究采用两种较为成熟的开源框架快速打造自己的图片下载功能。

1.1使用Android-Universal-Image-Loader框架

一般情况下,Android应用图片下载都是使用HttpURLConnection对象来实现并完成[3],因此最直接的办法就是使用此对象自定义下载图片方法,但这种方式需要编写较多的代码,而且运行效率和灵活性也较差,于当前的实际项目开发中已很少采用。Android-Universal-Image-Loader框架是一個专门用于图片下载的开源项目,能够较好地实现图片的异步下载功能,因而可以满足大部分应用对图片下载功能的需求。

使用此框架首先要从以下网址:

https://github.com/nostra13/Android-Universal-Image-Loader 下载jar包:

universal-image-loader-1.8.6-with-sources.jar。

此后,通过一个较为简单的案例来说明如何使用该框架实现图片的下载。

1.1.1 图片下载过程

(1)初始化ImageLoaderConfiguration对象(全局的,在整个application中初始化configuration,配置缓存、加载线程等)

ImageLoaderConfiguration config = new ImageLoaderConfiguration{ … }

以上的配置选项有很多,可以根据个人需求进行选择,不是所有都要进行配置。

配置了ImageLoaderConfiguration后,调用以下方法来实现初始化:

ImageLoader.getInstance().init(config); //全局初始化此配置

注意:ImageLoaderConfiguration 配置中的.discCacheFileNameGenerator()方法是将缓存下来的文件以什么方式命名,其中可以调用的方法有:

new Md5FileNameGenerator() //使用MD5对UIL进行加密命名

new HashCodeFileNameGenerator() //使用HASHCODE对UIL进行加密命名

(2)创建图片显示选项:DisplayImageOptions options(根据不同的加载图片的相应显示而构造不同的选项,主要设定图片加载过程中显示配置,缓存,显示动画)。

DisplayImageOptions options;

options = new DisplayImageOptions.Builder()

.showStubImage(R.drawable.ic_launcher)// 设置图片在下载期间显示的图片

以上的配置选项有很多,可以根据个人需求进行选择,但并非所有都需要进行配置。

(3)通过ImageLoader下载并显示图片。

ImageLoader imageLoader = ImageLoader.getInstance(); // 使用

ImageLoader进行图片加载的时候,先要实例化ImageLoader,调用以下方法进行实例化,而且在每个布局里面都要实例化后再使用。

imageLoader.displayImage(imageUrls[position], holder.image, options, loadingListener);// 第一个参数是uri,第二个参数是显示图片的imageView,第三个参数是最新构造完成的图片显示选项,第四个参数是加载的回调方法,displayImage有很多重载方法,这只是其中一种。

1.1.2 框架优势分析

通过对以上案例的测试和分析,会发现此框架主要具有如下优势:

(1)多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets以及drawable等;

(2)支持随意配置ImageLoader,例如线程池、图片下载器、内存缓存策略,硬盘缓存策略、图片显示选项以及其他的一些配置;

(3)支持图片的内存缓存,文件系统缓存或者SD卡缓存;

(4)支持图片下载过程的监听;

(5)根据控件(ImageView)的大小对Bitmap进行裁剪,严格Bitmap占用过多的内存;

(6)较好地控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中。滑动过程中暂停加载图片,停止滑动时则实行图片加载;

(7)在较慢的网络下对图片提供加载功能。

1.2使用volley框架

Volley是谷歌公司于2013年发布的Android平台上的网络通信库,能使网络通信更快,更简单,更健壮,并且更加适用于通信频繁但数据量不大的场景。

使用此框架首先要从以下网址:

https://github.com/mcxiaoke/android-volley 下载项目并导出jar包。

volley框架本身提供了几种主要的图片下载方法,下面通过小案例对其进行详细说明。

1.2.1 使用ImageRequest下载图片

首先需要获取到一个RequestQueue對象,可以调用如下方法获取得到:

RequestQueue mQueue = Volley.newRequestQueue(context);

接下来需要实例化一个ImageRequest对象了,代码如下所示:

ImageRequest imageRequest = new ImageRequest(

"http://www.baidu.com/img/bdlogo.png",

new Response.Listener() {

… }

});

在此之后,将这个ImageRequest对象添加到RequestQueue里即可,如下所示:

mQueue.add(imageRequest);

1.2.2 使用ImageLoader下载图片

首先,新建一个ImageLoader对象,代码如下所示:

ImageLoader imageLoader = new ImageLoader(mQueue, new ImageCache() {

public void putBitmap(String url, Bitmap bitmap) {

}

public Bitmap getBitmap(String url) {

return null;

}

});

可以看到,ImageLoader的构造函数接收两个参数,第一个参数就是RequestQueue对象,第二个参数是一个ImageCache对象,这里首先新建一个空的ImageCache的实现即可得到。

接下来需要获取一个ImageListener对象,代码如下所示:

ImageListener listener = ImageLoader.getImageListener(imageView,

R.drawable.default_image, R.drawable.failed_image);

研究中,通过调用ImageLoader的getImageListener()方法能够获取到一个ImageListener对象,getImageListener()方法接收三个参数,第一个参数指定用于显示图片的ImageView控件,第二个参数指定加载图片的过程中显示的图片,第三个参数指定加载图片失败的情况下显示的图片。

最后,调用ImageLoader的get()方法来加载图片,代码如下所示:

imageLoader.get("http://www.baidu.com/img/bdlogo.png", listener);

get()方法接收两个参数,第一个参数就是图片的URL地址,第二个参数则是新近获取得到的ImageListener对象。

1.2.3 NetworkImageView的用法

除了以上两种方式之外,Volley还提供了第三种方式来加载网络图片,即使用NetworkImageView。不同于以上两种方式,NetworkImageView是一个自定义控件,是继承自ImageView的,具备ImageView控件的所有功能,并且在原生的基础之上引入了加载网络图片的功能。NetworkImageView控件的用法要比前两种方式更加简单,大致可以分为以下五步:

(1)创建一个RequestQueue对象。

(2)创建一个ImageLoader对象。

(3)在布局文件中添加一个NetworkImageView控件。

(4)在代码中获取该控件的实例。

(5)设置要加载的图片地址。

1.2.4 volley框架的使用特点

(1)volley 适用于轻量高并发的网络请求, 能够请求网络的数据全部保存在内存中,因此不适合请求较大的数据,比如大文件、流媒体等。

(2)同一个程序中最好共用一个 RequestQueue。

(3)可以根据接口的放回数据类型定制任意的 Request,volley 已经默认为我们实现了 StringRequest、JsonArrayRequest、JsonObjectRequest、ImageRequest四个请求类型。

2图片上传

图片上传在Android应用开发中也是一个会经常遇到的问题,比如用户头像的上传、身份证照片的上传等。上传图片的功能其实就是获得图片的路径,创建文件,并将图片转化为字节流写入到request[4],再發送该请求,因此如果完全由用户自身实现就要使用到HttpURLConnection 类和输入输出流,同事需要编写较多的代码。这里为了实现图片的高效上传,研究仍然采用了开源框架的方式,现介绍以下两种较为常用的开源框架。

2.1使用android-async-http框架

使用此框架首先要从以下网址:

https://github.com/loopj/android-async-http下载项目并导出jar包。

使用此框架上传文件比较简单,主要通过RequestParams类就可以完成文件的上传,关键代码如下。

(1)添加文件对象用于上传

File myFile = new File("/path/to/myPic.png");

RequestParams params = new RequestParams();

try {

params.put("profile_picture", myFile);

} catch(FileNotFoundException e) {}

(2)添加字节数组用于上传

byte[] myByteArray = bytes;

RequestParams params = new RequestParams();

params.put("file", new ByteArrayInputStream(myByteArray), " myPic.png"");

2.2使用xUtils框架

使用此框架首先要从以下网址:https://github.com/wyouflf/xUtils下载项目并导出jar包。

2.2.1 使用xUtils框架上传图片的步骤

(1)创建并实例化HttpUtils类。

(2)创建并实例化HttpParams对象。

(3)创建并实例化HttpHandler对象, 将DefaultHttpClient的实例通过参数形式,传给HttpHandler。

(4)创建并实例化HttpRequest对象,在此对象中,封装了method、 url 以及params后,再通过HttpHandler对象来执行这一request,并最终调用DefaultHttpClient来执行同一request, 返回HttpResponse。

2.2.2 框架在图片上传方面的特点优势

(1)支持大文件上传,上传大文件不会oom(内存耗尽)问题[5];

(2)加载bitmap的时候,无需考虑bitmap加载过程中出现的oom问题;另外,有关android容器快速滑动时印发的图片错位等现象也已一并消除;

(3)内存管理使用lru算法,实现了对bitmap内存的搞笑管理;

(4)可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画。

3图片压缩

在android应用开发中,压缩图片的目的有两个:第一,避免占用内存过多;第二,如果要上传图片,而图片又较大,则会耗费流量,这时就需要对其进行优质压缩。

(1)避免内存过多的压缩方法

图片是要显示在界面组件上的,相应地就要用到Bitmap。 Bitmap在内存中的大小只和图片尺寸及色彩模式有关,若想改变Bitmap在内存中的大小,或者选择改变尺寸,或者选择改变色彩模式[6]。

(2)避免上传費流量的压缩方法

具体来说,既可改变图片尺寸,也可改变色彩模式,或者改变图片质量都行。正常情况下,需首先改变图片尺寸和色彩模式,其后改变图片质量。

(3)压缩方法的程序实现

根据Bitmap压缩图片质量,关键代码如下:

public static Bitmap cQuality(Bitmap bitmap){

ByteArrayOutputStream bOut = new ByteArrayOutputStream();

bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bOut);

ByteArrayInputStream bInt = new ByteArrayInputStream(bOut.toByteArray());

Bitmap newBitmap = BitmapFactory.decodeStream(bInt);

if(newBitmap!=null){

return newBitmap;

}else{

return bitmap;

}

}

改变图片大小的压缩算法,关键代码如下:

public static boolean getCacheImage(String filePath,String cachePath){

OutputStream out = null;

BitmapFactory.Options option = new BitmapFactory.Options();

option.inJustDecodeBounds = true; //设置为true,只读尺寸信息,不加载像素信息到内存

Bitmap bitmap = BitmapFactory.decodeFile(filePath, option); //此时bitmap为空

int be = 1; //be = 1代表不缩放

option.inSampleSize = be; //设置缩放比例

bitmap = BitmapFactory.decodeFile(filePath, option);

return bitmap.compress(CompressFormat.JPEG, 100, out);

}

根据项目需求,也可以把以上两种压缩方法相结合,用于进一步提高压缩效率。

4结束语

本文内容讨论了如何在Android应用开发中实现图片的高效处理,主要包括图片的下载、上传和压缩功能的实现,其中解决方案主要采用了当前几种比较成熟的开源框架。文章结合典型案例对图片处理的方法、步骤、注意事项进行了详细的阐述,同时通过严谨的分析和论证说明此种解决方案在方法上可行、而且高效。

参考文献:

[1]陈岑. 基于Android移动应用的网络图片传输与存储的设计与实现[D].北京:北京邮电大学,2014.

[2]项亮. 基于移动平台的图片制作系统设计与实现[D]. 上海:上海交通大学,2012.

[3]陈德春. Android优化技术详解 [M]. 北京:清华大学出版社,2014.

[4]舒尚春. 基于Android 的电子相框的设计与实现[J]. 电子技术与软件工程,2013,6(12):68-69.

[5]陈文,郭依正. 深入理解Android网络编程:技术详解与最佳实践[M]. 北京:机械工业出版社,2013.

[6]邹绍武,苏贵斌. Android应用开发中图片压缩技术的研究应用[J]. 计算机技术与发展,2015,25(6):106-109.