此文章是记录我在项目中如何使用Fresco,以及遇到的问题,还有相对应的解决方案。
1.添加防盗链;
2.直接下载图片,不需要控件去调用;
3.如何实现既要求可以从相册选取,又可以直接网络下载的圆角图片;
一、Fresco集成以及使用方法的中文官网地址:点击打开链接
二、正常的操作流程我就不再赘述,我接下来主要介绍我们项目中遇到的问题。
1、由于我们公司对于图片安全要求比较严格,需要加防盗链,所以介绍Fresco添加防盗链的方法如下:
public static void initFresco(Context context) {
ImagePipelineConfig config = OkHttpImagePipelineConfigFactory
.newBuilder(context, getOkHttpClientForFresco()).build();
Fresco.initialize(context, config);
}
private static OkHttpClient getOkHttpClientForFresco() {
OkHttpClient client;
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.addInterceptor(new HeaderInterceptor())
.connectTimeout(20, TimeUnit.SECONDS);
client = builder.build();
return client;
}
private static class HeaderInterceptor implements Interceptor {
private HashMap<String, String> mHeadMap;
private HeaderInterceptor() {
mHeadMap = new HashMap<>();
}
@Override
public Response intercept(Chain chain) throws IOException, BaseException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
for (String s : mHeadMap.keySet()) {
builder.addHeader(s, mHeadMap.get(s));
}
builder.addHeader("Referer", "xxxx");
builder.addHeader("Cookie", "xxx");
request = builder.build();
return chain.proceed(request);
}
}
2、由于之前我们用到的图片有圆角的,虽然Fresco官网提供了设置圆角的方法,但是这只是限于调用下载api的时候,我们所用到的场景是有时候需要从拍照获取,有时候需要从网络下载,所以这个设置圆角的api并不能满足所有的场景,于是我就将从拍照获取的Bitmap进行剪裁,剪裁成圆角图片,代码如下:
扫描二维码关注公众号,回复:
1212141 查看本文章
public static Bitmap getRoundRectBitmap(Bitmap bitmap, int radius) {
Bitmap target = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), ARGB_8888);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
int bmWidth = target.getWidth();
int bmHeight = target.getHeight();
final Rect rect = new Rect(0, 0, bmWidth, bmHeight);
final RectF rectF = new RectF(0, 0, bmWidth, bmHeight);
Canvas canvas = new Canvas(target);
paint.setXfermode(null);
canvas.drawRoundRect(rectF, radius, radius, paint);
paint.setXfermode(new PorterDuffXfermode(SRC_IN));
canvas.drawBitmap(bitmap, rect, rectF, paint);
return target;
}
3、Fresco是没有一个单独的api直接用于图片下载,而不需要控件调用的,需要自己去实现,解决办法如下:(ps:其中onGetFrescoImgListener是自己定义的一个interface,大家可以自行去修改)
/**
* 根据url下载图片,返回字节数组
*/
public static void frescoDownloadImg(@NonNull String url, @NonNull Activity context, @Nullable OnGetFrescoImgListener listener) {
Uri uri = Uri.parse(url);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
ImageRequest imageRequest = builder.build();
// 获取未解码的图片数据
DataSource<CloseableReference<PooledByteBuffer>> dataSource = imagePipeline.fetchEncodedImage(imageRequest, context);
dataSource.subscribe(new BaseDataSubscriber<CloseableReference<PooledByteBuffer>>() {
private byte[][] data = new byte[1][1];
@Override
public void onNewResultImpl(DataSource<CloseableReference<PooledByteBuffer>> dataSource) {
if (!dataSource.isFinished()) {
return;
}
CloseableReference<PooledByteBuffer> imageReference = dataSource.getResult();
if (imageReference != null) {
final CloseableReference<PooledByteBuffer> closeableReference = imageReference.clone();
try {
PooledByteBuffer pooledByteBuffer = closeableReference.get();
InputStream inputStream = new PooledByteBufferInputStream(pooledByteBuffer);
data[0] = input2byte(inputStream);
context.runOnUiThread(new Thread(() -> {
if (listener != null) {
listener.getFrescoImgByteSuccess(data[0]);
}
}));
} catch (IOException e) {
e.printStackTrace();
} finally {
closeableReference.close();
}
}
}
@Override
public void onFailureImpl(DataSource dataSource) {
context.runOnUiThread(new Thread(() -> {
if (listener != null) {
listener.getFrescoImgByteFail(data[0]);
}
}));
}
}, Executors.newSingleThreadExecutor());
}
public interface OnGetFrescoImgListener {
void getFrescoImgByteSuccess(byte[] data);
void getFrescoImgByteFail(byte[] data);
}
使用方法如下:
/**
* Fresco直接通过Url下载图片获取字节数组(异步)
*/
private void getBitmapFromUrl(String title, String link, String desc, String url, int flag) {
FrescoUtil.frescoDownloadImg(url, (Activity) mContext, new FrescoUtil.OnGetFrescoImgListener() {
@Override
public void getFrescoImgByteSuccess(byte[] data) {
startShareWechat(title, link, desc, data, flag);
}
@Override
public void getFrescoImgByteFail(byte[] data) {
startShareWechat(title, link, desc, data, flag);
}
});
}
4、接下来我贴一下我自己封装的FrescoUtil,还是个不怎么成熟的程序员,希望大家多多提建议,多多指教,接受批评和指正。
public class FrescoUtil {
public static void initFresco(Context context) {
ImagePipelineConfig config = OkHttpImagePipelineConfigFactory
.newBuilder(context, getOkHttpClientForFresco()).build();
Fresco.initialize(context, config);
}
private static OkHttpClient getOkHttpClientForFresco() {
OkHttpClient client;
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.addInterceptor(new HeaderInterceptor())
.connectTimeout(20, TimeUnit.SECONDS);
client = builder.build();
return client;
}
private static class HeaderInterceptor implements Interceptor {
private HashMap<String, String> mHeadMap;
private HeaderInterceptor() {
mHeadMap = new HashMap<>();
}
@Override
public Response intercept(Chain chain) throws IOException, BaseException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
for (String s : mHeadMap.keySet()) {
builder.addHeader(s, mHeadMap.get(s));
}
builder.addHeader("Referer", "xxx");
builder.addHeader("Cookie", "xxx");
request = builder.build();
return chain.proceed(request);
}
}
public interface OnGetFrescoImgListener {
void getFrescoImgByteSuccess(byte[] data);
void getFrescoImgByteFail(byte[] data);
}
/**
* SimpleDraweeView 加载 url
*/
public static void frescoSetImg(@NonNull SimpleDraweeView iv,
String url) {
iv.setImageURI(url);
}
/**
* SimpleDraweeView 设置 GenericDraweeHierarchy 加载 url
*/
public static void frescoSetImg(@NonNull SimpleDraweeView iv,
@NonNull GenericDraweeHierarchy hierarchy,
String url) {
iv.setHierarchy(hierarchy);
iv.setImageURI(url);
}
/**
* GenericDraweeHierarchy 设置 占位图、失败图,SimpleDraweeView 设置 GenericDraweeHierarchy 加载 url
*/
public static void frescoSetImg(@NonNull SimpleDraweeView iv,
String url,
int placeholderImageResId,
int failureImageResId,
@NonNull Context context) {
frescoSetRoundImg(iv, url, placeholderImageResId, failureImageResId, null, null, context, null);
}
/**
* GenericDraweeHierarchy 设置 占位图、占位图的何种比例缩放(可以传null)、失败图、失败图的何种比例缩放(可以传null),SimpleDraweeView 设置
* GenericDraweeHierarchy 加载 url
*/
public static void frescoSetImg(@NonNull SimpleDraweeView iv,
String url,
int placeholderImageResId,
int failureImageResId,
@Nullable ScalingUtils.ScaleType placeholderScale,
@Nullable ScalingUtils.ScaleType failureImageScaleType,
@NonNull Context context) {
frescoSetRoundImg(iv, url, placeholderImageResId, failureImageResId, placeholderScale, failureImageScaleType, context, null);
}
/**
* GenericDraweeHierarchy 设置 占位图、失败图,SimpleDraweeView 设置 GenericDraweeHierarchy 加载 url
*/
public static void frescoSetImg(
@NonNull SimpleDraweeView iv,
String url,
int placeholderImageResId,
int failureImageResId,
@Nullable RoundingParams roundingParams,
@NonNull Context context) {
frescoSetRoundImg(iv, url, placeholderImageResId, failureImageResId, null, null, context, roundingParams);
}
/**
* GenericDraweeHierarchy 设置 占位图、占位图的何种比例缩放、失败图、失败图的何种比例缩放、圆角设置,SimpleDraweeView 设置
* GenericDraweeHierarchy 加载 url
*/
public static void frescoSetRoundImg(@NonNull SimpleDraweeView iv,
String url,
int placeholderImageResId,
int failureImageResId,
@Nullable ScalingUtils.ScaleType placeholderScale,
@Nullable ScalingUtils.ScaleType failureImageScaleType,
@NonNull Context context,
@Nullable RoundingParams roundingParams) {
GenericDraweeHierarchy genericDraweeHierarchy = GenericDraweeHierarchyBuilder.newInstance(context.getResources())
.setPlaceholderImage(placeholderImageResId)
.setFailureImage(failureImageResId)
.setRoundingParams(roundingParams)
.setPlaceholderImageScaleType(placeholderScale)
.setFailureImageScaleType(failureImageScaleType)
.build();
iv.setHierarchy(genericDraweeHierarchy);
iv.setImageURI(url);
}
/**
* 根据url下载图片,返回字节数组
*/
public static void frescoDownloadImg(@NonNull String url, @NonNull Activity context, @Nullable OnGetFrescoImgListener listener) {
Uri uri = Uri.parse(url);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
ImageRequest imageRequest = builder.build();
// 获取未解码的图片数据
DataSource<CloseableReference<PooledByteBuffer>> dataSource = imagePipeline.fetchEncodedImage(imageRequest, context);
dataSource.subscribe(new BaseDataSubscriber<CloseableReference<PooledByteBuffer>>() {
private byte[][] data = new byte[1][1];
@Override
public void onNewResultImpl(DataSource<CloseableReference<PooledByteBuffer>> dataSource) {
if (!dataSource.isFinished()) {
return;
}
CloseableReference<PooledByteBuffer> imageReference = dataSource.getResult();
if (imageReference != null) {
final CloseableReference<PooledByteBuffer> closeableReference = imageReference.clone();
try {
PooledByteBuffer pooledByteBuffer = closeableReference.get();
InputStream inputStream = new PooledByteBufferInputStream(pooledByteBuffer);
data[0] = input2byte(inputStream);
context.runOnUiThread(new Thread(() -> {
if (listener != null) {
listener.getFrescoImgByteSuccess(data[0]);
}
}));
} catch (IOException e) {
e.printStackTrace();
} finally {
closeableReference.close();
}
}
}
@Override
public void onFailureImpl(DataSource dataSource) {
context.runOnUiThread(new Thread(() -> {
if (listener != null) {
listener.getFrescoImgByteFail(data[0]);
}
}));
}
}, Executors.newSingleThreadExecutor());
}
三、总结
虽然花费了一个星期的时间去替换了项目的图片第三方加载库,但是也只是限于解决了问题,我还是有点不求甚解,这种感觉很不好,我会在接下来的时间去认真的研究下这个Fresco的原理,以及各种实现的源码,然后有机会再出一篇专门的分析文章,这次就是记录下项目中遇到的问题以及解决方案,希望可以帮助到大家。
四、用后感
其实用起来感觉没有这么方便,各种方法封装的不够,但是换句话说,灵活性比较高,可以自己去搞,也有一方面是自己能力不足,希望以后自己越来越好。