为了创建视觉上吸引人的应用程序,显示图像是必须的。了解如何在不牺牲性能的情况下在您的Android应用程序中高效地显示位图。在Android上显示图像的痛苦在开发具有视觉吸引力的应用程序时,显示图像是必须的。问题是Android操作系统不能很好地处理图像解码,迫使开发人员在执行某些任务时要小心,以免搞砸性能。Google写了一份关于高效显示位图的完整指南,我们可以按照这个指南来了解和解决Android操作系统在显示位图时的主要缺点。Android应用程序性能杀手按照Google的指南,我们可以列出在Android应用程序上显示图像时面临的一些主要问题。图像下采样无论视图大小如何,Android始终以全尺寸/尺寸解码和显示图像。因此,如果您尝试加载大图像,很容易在您的设备上抛出outOfMemoryError。为了避免这种情况,正如谷歌所说,我们应该使用BitmapFactory来解码图像,为inSampleSize参数设置一个值。图像大小除以inSampleSize以减少内存使用。publicstaticBitmapdecodeSampledBitmapFromResource(Resourcesres,intresId,intreqWidth,intreqHeight){//首先使用inJustDecodeBounds=true解码以检查尺寸finalBitmapFactory.Optionsoptions=newBitmapFactory.Options();options.inJustDecodeBounds=true;BitmapFactory.decodeResource(res,resId,options);//计算inSampleSizeoptions.inSampleSize=calculateInSampleSize(options,reqWidth,reqHeight);//使用inSampleSize设置options.inJustDecodeBounds=false解码位图;returnBitmapFactory.decodeResource(res,resId,options);}你可以手动设置inSampleSize,或者使用显示器的尺寸计算。publicstaticintcalculateInSampleSize(BitmapFactory.Optionsoptions,intreqWidth,intreqHeight){//图像的原始高度和宽度finalintheight=options.outHeight;finalintwidth=options.outWidth;intinSampleSize=1;if(height>reqHeight||width>reqWidth){finalinthalfHeight=height/2;finalinthalfWidth=width/2;//计算最大的SampleSize值,它是2的幂,并保持//高度和宽度都大于请求的高度和宽度。while((halfHeight/inSampleSize)>=reqHeight&&(halfWidth/inSampleSize)>=reqWidth){inSampleSize*=2;}}returninSampleSize;}异步解码即使在使用BitmapFactory时,图像解码也是在UI线程上完成的。这可能会冻结应用程序并导致ANR(“应用程序未响应应用程序未响应”)警报。这个很容易解决,只需要将解码过程放在工作线程上即可。一种方法是使用异常步骤,如Google指南中解释的那样:classBitmapWorkerTaskextendsAsyncTask{privatefinalWeakReferenceimageViewReference;私有数据=0;publicBitmapWorkerTask(ImageViewimageView){//使用弱引用确保ImageView可以被垃圾回收imageViewReference=newWeakReference(imageView);}//在后台解码图像。@OverrideprotectedBitmapdoInBackground(Integer...params){data=params[0];返回decodeSampledBitmapFromResource(getResources(),数据,100,100));}//完成后,查看ImageView是否仍然存在并设置位图。@OverrideprotectedvoidonPostExecute(Bitmapbitmap){if(imageViewReference!=null&&bitmap!=null){finalImageViewimageView=imageViewReference.get();if(imageView!=null){imageView.setImageBitmap(bitmAP);}}}}图像缓存每当图像被解码并放置在视图中时,Android操作系统默认会重复整个渲染过程,如果您打算在不同的地方显示相同的图像,或者由于多次重新加载,则会浪费宝贵的设备内存到应用程序生命周期或行为,那么这可能会特别烦人。为了避免占用太多内存,建议使用内存和磁盘缓存。接下来,我们将了解这些缓存之间的主要区别以及使用两者的好处。代码太复杂,无法在此处显示,因此请自行参考Google指南的位图缓存部分,了解如何实现内存和磁盘缓存。内存缓存:图像存储在设备内存中。内存访问速度很快。事实上,它比图像解码过程快得多,因此将图像存储在这里是让应用程序更快更稳定的好主意。内存缓存的唯一缺点是它只在应用程序的生命周期内存在,这意味着一旦应用程序被Android操作系统内存管理器关闭或杀死(全部或部分),存储在那里的所有图像都将丢失。请记住,必须将memcache设置为最大可用内存量。如果不这样做可能会导致臭名昭著的outOfMemoryError。磁盘缓存:图像存储在设备的物理内存(磁盘)中。只要有足够的空间,磁盘缓存就可以在应用程序启动后安全地存储图像。缺点是磁盘读写速度可能很慢,而且总是比访问内存缓存慢。因此,所有磁盘操作都必须在UI线程之外的工作线程上执行。否则,应用程序将冻结并引发ANR警报。每个缓存都有其优点和缺点,因此最佳做法是同时使用两者,并通过内存缓存从第一个可用的位置开始读取。***思考与EpicBitmapRenderer不知道大家有没有注意到,正如我在本文开头所说的,在Androidapp上显示图片真的是一件很头疼的事情。它并不像看起来那么简单。为了避免在每个项目中重复这些任务,我开发了一个100%免费和开源的Android库EpicBitmapRenderer。您可以在EpicBitmapRendererGitHub存储库中获取它,或在EpicBitmapRenderer网站上了解更多信息。EpicBitmapRenderer易于使用,并在每次图像解码操作中自动执行所有这些烦人的任务,因此您可以专注于应用程序开发。您只需将EpicBitmapRenderer依赖项添加到您的Gradle(要查看其他构建工具的替代方案,请参阅EpicBitmapRenderer文档的导入库部分)。compile'com.isaacrf.epicbitmaprenderer:epicbitmaprenderer:1.0'在EpicBitmapRenderer中解码图像很简单:只需调用所需的解码方法并管理结果。看看下面的例子,我们从URL中获取图像并将其显示在ImageVIew上。//示例3:从URL解码位图(异步)EpicBitmapRenderer.decodeBitmapFromUrl("http://isaacrf.com/wp-content/themes/Workality-Lite-child/images/IsaacRF.png",200,200,newOnBitmapRendered(){@OverridepublicvoidonBitmapRendered(Bitmapbitmap){//当ImageViewimgView=findViewById(R.id.imgSampleDecodeUrl);imgView.setImageBitmap(bitmap);}},newOnBitmapRenderFailed(){@OverridepublicvoidonBitmapRenderFailed(Exceptione){//如果Bitmap无法呈现Toast.makeText(MainActivity.this,"FailedtoloadBitmapfromURL",Toast.LENGTH_SHORT).show();}});根据CreativeCommonsAttribution-ShareAlike3.0UnportedLicense许可本文以及任何相关的源代码和文档授权许可翻译链接:http://www.codeceo.com/article/android-app-display-bitmaps.html英文原文:DisplayingBitmapsEfficientlyonAndroidApps