图片加载时项目中不可缺少的一个功能,很多程序员都会使用一些框架来帮助处理要加载的图像,往往在处理图片加载时很有可能会出现OOM的错误,这样会很蛋疼。现在主流的都是使用ImageLoader、Volley、Picasso,或者是一些自己封装的工具类。最近我发现一个新的图片加载框架Fresco是faceBook中使用的强大框架,代码简洁功能强大,可以很好的解决OOM的现象。
具体的配置我就略过,直接进入使用环节,如果想了解的话这是Fresco的官网(中文的)https://www.fresco-cn.org/docs/index.html
加载图片代码很简单,首先要在继承Application类里初始化
在MainActivity类里直接可以加载URLset到ImageView上,这里注意Fresco不接受相对路径,只能传绝对路径。
到这里我们代码功能就实现了,接下来是xml文件的设置
Fresco使用的是自定义的ImageView,里面的fresco标签要加上红框内的才可以(这里有个坑就是fresco的自定义属性不能提示,只能自己查官网复制,可能有的人能提示具体我还不太清楚为什么)
接下来是一些常用的自定义属性的具体意义和使用注意
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="20dp" // 不支持wrap_content 如果要设置宽高比, 需要在Java代码中指定setAspectRatio(1.33f);
android:layout_height="20dp" // 不支持wrap_content
fresco:fadeDuration="300"
fresco:actualImageScaleType="focusCrop" // 设置图片缩放. 通常使用focusCrop,该属性值会通过算法把人头像放在中间
fresco:placeholderImage="@color/wait_color" // 下载成功之前显示的图片
fresco:placeholderImageScaleType="fitCenter"
fresco:failureImage="@drawable/error"// 加载失败的时候显示的图片
fresco:failureImageScaleType="centerInside"
fresco:retryImage="@drawable/retrying"// 加载失败,提示用户点击重新加载的图片(会覆盖failureImage的图片)
fresco:retryImageScaleType="centerCrop"
fresco:progressBarImage="@drawable/progress_bar"// 提示用户正在加载,和加载进度无关
fresco:progressBarImageScaleType="centerInside"
fresco:progressBarAutoRotateInterval="1000"
fresco:backgroundImage="@color/blue"
fresco:overlayImage="@drawable/watermark"
fresco:pressedStateOverlayImage="@color/red"
fresco:roundAsCircle="false"// 是不是设置圆圈
fresco:roundedCornerRadius="1dp"// 圆角角度,180的时候会变成圆形图片
fresco:roundTopLeft="true"
fresco:roundTopRight="false"
fresco:roundBottomLeft="false"
fresco:roundBottomRight="true"
fresco:roundWithOverlayColor="@color/corner_color"
fresco:roundingBorderWidth="2dp"
fresco:roundingBorderColor="@color/border_color"
/>
到这里就完成了是不是很简单,可能有人会疑惑,既然是图片加载框架,图片保存到本地哪里呢?我也是找了很久才知道,Fresco并没有将图片下载到本地,而是缓存到本地注意是缓存到本地,我们只能找到缓存本地的文件复制到本地目录下或者下载到本地。下面我找了一个工具类就可以解决这个问题了。
public class FrescoUtil {
private static final String TAG = "FrescoUtil";
public static final String IMAGE_PIC_CACHE_DIR = Environment.getExternalStorageDirectory().getPath()+"/AndroidIamge/";
/**
* 保存图片
*
* @param activity
* @param picUrl
*/
public static void savePicture(String picUrl,Context context) {
File picDir = new File(IMAGE_PIC_CACHE_DIR);
if (!picDir.exists()) {
picDir.mkdir();
}
CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(ImageRequest.fromUri(Uri.parse(picUrl)),context);
File cacheFile = getCachedImageOnDisk(cacheKey);
if (cacheFile == null) {
downLoadImage(Uri.parse(picUrl),"down",context);
return;
} else {
copyTo(cacheFile,picDir,"down");
}
}
public static File getCachedImageOnDisk(CacheKey cacheKey) {
File localFile = null;
if (cacheKey != null) {
if (ImagePipelineFactory.getInstance().getMainDiskStorageCache().hasKey(cacheKey)) {
BinaryResource resource = ImagePipelineFactory.getInstance().getMainDiskStorageCache().getResource(cacheKey);
localFile = ((FileBinaryResource) resource).getFile();
} else if (ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache().hasKey(cacheKey)) {
BinaryResource resource = ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache().getResource(cacheKey);
localFile = ((FileBinaryResource) resource).getFile();
}
}
return localFile;
}
/**
* 复制文件
*
* @param src 源文件
* @param dst 目标文件
* @return
*/
public static boolean copyTo(File src, File dir, String filename) {
FileInputStream fi = null;
FileOutputStream fo = null;
FileChannel in = null;
FileChannel out = null;
try {
fi = new FileInputStream(src);
in = fi.getChannel();//得到对应的文件通道
File dst;
dst = new File(dir, filename + ".jpg");
fo = new FileOutputStream(dst);
out = fo.getChannel();//得到对应的文件通道
in.transferTo(0, in.size(), out);//连接两个通道,并且从in通道读取,然后写入out通道
return true;
} catch (IOException e) {
return false;
} finally {
try {
if (fi != null) {
fi.close();
}
if (in != null) {
in.close();
}
if (fo != null) {
fo.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
public static void downLoadImage(Uri uri, final String filename, Context context) {
ImageRequest imageRequest = ImageRequestBuilder
.newBuilderWithSource(uri)
.setProgressiveRenderingEnabled(true)
.build();
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>>
dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
public void onNewResultImpl(Bitmap bitmap) {
if (bitmap == null) {
Log.e(TAG,"保存图片失败啦,无法下载图片");
}
File appDir = new File(IMAGE_PIC_CACHE_DIR);
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = filename + ".jpg";
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
assert bitmap != null;
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailureImpl(DataSource dataSource) {
}
}, CallerThreadExecutor.getInstance());
}
}
然后我们在加载时候改造一下
这样图片就会加载到本地了,具体路径和文件名字可以自行去更改