详谈Android从文件读取图像显示的效率问题
因为从文件读取图像到bitmap是一件比较费时的事情,所以研究了一下几种可行的办法,并做了对比。
首先解释一下为什么耗时,这是因为,在从jpg或者png文件中读取bitmap时,一来需要对外存进行操作并且图像文件一般都比较大,二来在创建bitmap时,基本都需要对原始图像做操作,例如:降采样、剪切、旋转等等。所以如何高效的读取图片并呈现出来,是一个很值得研究的问题。
根据我的想法,大致想出了3种方案:
1、在当前的ui线程直接读取并操作图像,然后呈现。
2、新开一个子线程读取并操作图像,然后利用bundle中serializable的相关方法将其传回ui线程并呈现。
3、其他做法与2一样,但是利用的是bundle中parcelable的相关方法。
方法一
start_time = system.currenttimemillis(); bitmapfactory.options options=new bitmapfactory.options(); options.injustdecodebounds = true; bitmap bitmap=bitmapfactory.decodefile(path,options); options.insamplesize=calculatesize(options,width,height); options.injustdecodebounds=false; //整个图像,下采样 bitmap=bitmapfactory.decodefile(path,options); //部分图像 bitmap patch=bitmap.createbitmap(bitmap, 10, 10, 100, 100); end_time = system.currenttimemillis(); log.v("bitmaptest", "ui time consume:"+(end_time - start_time)); imageview.setimagebitmap(bitmap); patchview.setimagebitmap(patch);
操作很简单,先将图片文件的尺寸等信息读取出来, 然后根据其尺寸计算其缩放比例,并将图片中的一部分剪切出来。最后将图片显示在imageview空间上。大致测了几十次,得到的平均消耗时间为:72.75ms
方法二
启动子线程
start_time = system.currenttimemillis(); string path=environment.getexternalstoragedirectory().getpath()+file.separator+"image1.jpg"; imgthread imgthread=new imgthread(msghandler,path,width,height); imgthread.start();
子线程中的操作,与1基本相同
bitmapfactory.options options=new bitmapfactory.options(); options.injustdecodebounds = true; bitmap bitmap=bitmapfactory.decodefile(path,options); options.insamplesize=calculatesize(options,width,height); options.injustdecodebounds=false; //整个图像,下采样 bitmap=bitmapfactory.decodefile(path,options); //部分图像 bitmap patch=bitmap.createbitmap(bitmap, 10, 10, 100, 100); array=new arraylist<bitmap>(2); array.add(bitmap); array.add(patch); //serializable传递 bundle bundle=new bundle(); bundle.putserializable("img", array); //parcelable传递 /* mylist l=new mylist(parcel.obtain()); l.array=array; bundle.putparcelable("img", l); */ message msg= new message(); msg.what=1; msg.setdata(bundle); handler.sendmessage(msg);
将bitmap传回到ui线程并呈现
bundle bundle=msg.getdata(); //serializable传递 arraylist<bitmap> array=(arraylist<bitmap>) bundle.getserializable("img"); //parcelable传递 //mylist l=(mylist)bundle.getparcelable("img"); //arraylist<bitmap> array=l.array;//=(arraylist<bitmap>) bundle.getparcelable("img"); bitmap bitmap=array.get(0); bitmap patch=array.get(1); end_time = system.currenttimemillis(); log.v("bitmaptest", "th time consume:"+(end_time - start_time)); imageview.setimagebitmap(bitmap); patchview.setimagebitmap(patch);
方法二的平均消耗时间为:83.93ms
方法三
该方法需要新建一个类用来实现parcelable接口
package com.example.bitmaptest; import java.util.arraylist; import android.os.parcel; import android.os.parcelable; public class mylist implements parcelable{ public arraylist array; public mylist(parcel in) { in.readvalue(null); } @override public int describecontents() { return 0; } @override public void writetoparcel(parcel dest, int flags) { dest.writevalue(array); } public static final parcelable.creator<mylist> creator = new parcelable.creator<mylist>() { @override public mylist createfromparcel(parcel source) { return new mylist(source); } @override public mylist[] newarray(int size) { return new mylist[size]; } }; }
在子线程中的操作
//parcelable传递 mylist l=new mylist(parcel.obtain()); l.array=array; bundle.putparcelable("img", l);
方法三的平均消耗时间为:87.35ms
结果分析
三种方法都是在魅族mx1型号的手机上测试的,理论上方法三应该比方法二快,但至少根据我的实验结果来看,在传送小数据量时(图像大概是几mb或几百kb),数据的传递耗时并不是关键,两种方法的耗时差不多。方法一由于没有使用线程间的数据传递,因此耗时是最少的。
因此,我总结得到如下结论:
1、如果必须等到图像加载完成才允许用户操作的这种场景,可以直接在ui线程做图像的操作,这时可以添加一个progressdialog用来提示正在加载。
2、如果需要一边允许用户操作一边加载图像的话,应该新开一个子线程,但是在数据量不大的情况下,serializable和parcelable差距不大。
3、总而言之,图像的尺寸和数量不大时,在ui线程直接做图像读取等操作即可,但比较大时还是最好开个子线程。
以上这篇详谈android从文件读取图像显示的效率问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。