本文首先介绍一下 Facebook 推出的这个强大的图片加载框架以及一些简单的使用,在后续的文章中会逐步深入探究它的实现原理以及一些值得学习的编程思想。
Android 系统是一个多用户的 Linux 系统,每一个应用会分配一个独立的 Linux 用户进程,基于这样的的运行机制,应用在运行过程中能够使用的内存大小是有限的,一般在设备出厂后,单个应用可分配的最大内存就确定下来了(定义在 /system/build.prop 文件中的 dalvik.vm.heapstartsize = 128),如果应用需要使用的内存超出了这个大小,便会引起 OOM(Out Of Memory) 错误,也就是所谓的内存泄漏,此时进程会被系统强制 kill 掉,导致应用无法继续正常运行。因此,在进行 Android 应用开发的时候,要尽可能的避免引发内存泄漏问题。
在 Android 应用中,图片资源(Bitmap)通常需要占用大量内存,图片资源占用内存的计算公式为:
图片占用的内存 = 图片长度 * 图片宽度 * 单位像素占用的字节数
其中长度和宽度的单位是像素(px),单位像素占用的字节数以 ARGB_8888 格式为例,其他图片格式单位像素占用字节数可在 官方文档 中查看。以一张 500 * 500px 的图片为例,如果在应用中加载,所需要占用的内存为:
500 * 500 * 4 = 1,000,000字节(大约1M)
如果需要连续加载 10 张图片,则占用内存 10M,以这样的内存消耗,如果不能及时清理图片资源回收内存,极容易引起内存泄漏。因此,在 Android 应用开发过程中,需要重视图片资源的处理。
在 Android 开发中,需要重视图片资源的处理,而图片资源的处理并不简单,涉及到很多方面.比如,何时加载图片何时回收图片,图片是否需要压缩以及怎样压缩,下载网络图片和占位图的处理,是否需要缓存以及怎样缓存,图片圆角处理以及其他修改等许多问题需要解决,而解决这些问题需要丰富的经验以及大量的时间,才能保证尽量减少 OOM 错误,在 Fresco 之前,已经有一些优秀的第三方图片加载库能够帮助开发者处理快速集成图片处理框架,比如 Picasso , Universal-Image-Loader , Glide 等,使用其中任意一个都能够很好的集成图片处理框架。而 Fresco 综合了之前的图片加载库的优点,并利用本地代码做了性能优化,实现了更好的内存管理和更强大的功能,是一个值得深入学习的图片加载库。
Fresco 是 Facebook 推出的一个强大的图片加载框架,使用它能够很快速的完成一些日常开发中需要用到图片的需求,包括图片加载与缓存,图片处理以及一些实用功能,官方文档 中详细介绍了它的配置与使用。相比于其他图片加载框架,具有如下特性:
关于 Fresco 的底层实现以及内存分配,将在后续文章中介绍,本文主要介绍 Fresco 的配置与圆角图片的使用
按照文档的描述,首先需要进行项目引入,如果使用 AndroidStudio 开发,需要在对应 Module 的 build.gradle 文件中添加如下配置代码:
dependencies {
compile 'com.facebook.fresco:fresco:0.7.0+'
}
Eclipse 用户则需要先下载 library,然后导入到项目中,具体操作可以参见 官方文档
一般加载图片都需要从网络加载,所以要记得在 AndroidManifest.xml 文件中添加网络访问权限,以及一些开发需要用到的权限。等待 AndroidStudio 配置完成后便可以开始使用 Fresco 了
在使用时,首先需要进行初始化,通常是在 Application 中进行全局初始化:
public class BaseApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Fresco.initialize(this);
}
}
初始化完成后便可以使用 Fresco 加载显示图片了,下面是一个最简单的使用方法
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="8dp"
fresco:placeholderImage="@mipmap/ic_launcher"/>
Uri imgUrl = Uri.parse("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png");
SimpleDraweeView urlImg = (SimpleDraweeView) findViewById(R.id.sdv_image_url);
urlImg.setImageURI(imgUrl);
以上,便完成了 Fresco 的最基本使用,实现了从网络下载图片并显示到对应的视图上,下载的图片将会自动缓存(关于 Fresco 的缓存策略将在后续文章中介绍),在下载没有完成或者网络错误导致下载失败的时候,视图会显示占位图,直到下载完成。当然还有很多可自定义设置来实现一下常用的功能,比如下载失败后点击图片会尝试重新下载,这些功能都可以很方面快速的实现。
在不使用 SimpleDraweeView 时,要实现带圆角的图片,通常的做法是编写一个继承自 ImageView 的自定义 View,然后绘制一个带圆角的 Bitmap,这种方式需要重新创建一个带圆角的 Bitmap 对象,而在 Fresco 中,并不通过这种方式来实现(关于圆角的实现原理,将在下篇文章中介绍)
在使用 SimpleDraweeView 时,实现图片圆角有两种方式:
BITMAP_ONLY(默认):默认使用一个 shader 绘制圆角,只对占位图和实际显示的图有效,加载失败和重新下载的示意图都没有圆角效果,这种方式实现圆角图片,会有以下几种限制
OVERLAY_COLOR:在原始图片上叠加一个 solid color,类似 PS 中图层的概念,在原图层上添加一个和背景色相同颜色的圆角空心图层,这种方式实现的圆角图片没有上述限制,但是由于这种方式是通过覆盖一层和背景色相同的图层来实现的,因此只有在背景颜色不变的情况下才能获得较好的效果
下面通过代码演示通过不同方式实现圆角
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_image_circle"
android:layout_width="100dp"
android:layout_height="100dp"
fresco:placeholderImage="@mipmap/img_test"
fresco:roundAsCircle="true"/>
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_image_round"
android:layout_width="100dp"
android:layout_height="100dp"
fresco:placeholderImage="@mipmap/img_test"
fresco:roundedCornerRadius="20dp"
fresco:roundBottomLeft="false"/>
在代码中设置圆角
RoundingParams bitmapOnlyParams = RoundingParams.fromCornersRadius(40)
.setRoundingMethod(RoundingParams.RoundingMethod.BITMAP_ONLY);
roundImg.getHierarchy().setRoundingParams(bitmapOnlyParams);
运行效果:
通过这种方式设置圆角,还支持 4 种不同半径的圆角,但是无法在 xml 中设置,需要在 java 代码中设置
RoundingParams diffParams = RoundingParams.fromCornersRadii(50, 100, 150, 200);
diffRoundImg.getHierarchy().setRoundingParams(diffParams);
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_image_lay"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="8dp"
fresco:placeholderImage="@mipmap/img_test"
fresco:roundedCornerRadius="20dp"
fresco:roundWithOverlayColor="#0000ff"/>
如果在代码中设置,则 xml 中的属性会失效
RoundingParams overlayColor = RoundingParams.fromCornersRadius(80)
.setRoundingMethod(RoundingParams.RoundingMethod.OVERLAY_COLOR)
.setOverlayColor(Color.WHITE);//设置覆盖层颜色,这里设置为白色,xml中的属性设置会失效,以这里的属性为准
layRoundImg.getHierarchy().setRoundingParams(overlayColor);
以上,Fresco 中使用圆角的两种方法及其使用就介绍到这里,演示代码见 GitHub,下篇文章将深入分析圆角的实现原理以及 Android 中一些能够实现圆角的方案。