8.4.2 Fresco

时间:2021-08-14 09:15:00

Fresco是Facebook公司的黑科技:http://fresco-cn.org/

  真三级缓存,变换后的BItmap(内存),变换前的原始图片(内存),硬盘缓存。在内存管理上做到了极致。对于重度图片使用的APP应该是非常好的。它一般是直接使用SimpleDraweeView来替换ImageView

  注意事项:SimpleDraweeView的width和height属性必须是明确值,而不能直接用wrap_content这种内容填充的数值;除非宽度和高度有一个是固定的,然后设置了二者的比例(setAspectRatio),则另一个可以用wrap_content,其实相当于二者都是固定的。正常情况下,一个SimpleDraweeView的各种属性,既可以在布局文件里面设置(如上面的代码)也可以在Java代码里设置,作用是一样的。但当SimpleDraweeView被被一些第三方自定义View包裹的时候,比如一个可下拉刷新的第三方ListView,则此时在布局文件中的一些属性居然是无效的!

  ImageLoader 等传统第三方图片处理SDK 不同,Fresco 是基于控件级别的,所以我们把程序中显示网络图片的ImageView 都替换为SimpleDraweeView 。

Fresco 的原理是,设计了一个Image Pipeline 的概念,它负责先后检查内存、磁盘文件(Disk),如果都没有再从网络下载图片。我们可以像配置ImageLoader 那样配置Fresco 中的Image Pipeline,使用ImagePipelineConfig来做这个事情。
  Fresco 有3 个线程池,其中3 个线程用于网络下载图片,2 个线程用于磁盘文件的读写,还有2 个线程用于CPU 相关操作,比如图片解码、转换,以及放在后台执行的一些费时操作。
  接下来介绍Fresco 三层缓存的概念。这才是Fresco 最核心的技术,它比其他图片SDK吃内存小,就在于这个全新的缓存设计。

  • 第一层:Bitmap 缓存:在Android 5.0 系统中,考虑到内存管理有了很大改进,所以Bitmap 缓存位于Java 的堆(heap)中。 ‰而在Android 4.x 和更低的系统,Bitmap 缓存位于ashmem(匿名共享内存) 中,而不是位于Java 的堆(heap)中。这意味着图片的创建和回收不会引发过多的GC,从而让App 运行得更快。当App 切换到后台时,Bitmap 缓存会被清空。
  • 第二层:内存缓存:内存缓存中存储了图片的原始压缩格式。从内存缓存中取出的图片,在显示前必须先解码。当App 切换到后台时,内存缓存也会被清空。
  • 第三层:磁盘缓存:磁盘缓存,又名本地存储。磁盘缓存中存储的也是图片的原始压缩格式。在使用前也要先解码。当App 切换到后台时,磁盘缓存不会丢失,即使关机也不会。

Fresco 有很多高级的应用,对于大部分App 而言,基本还用不到。

Image pipeline 负责完成加载图像,变成Android设备可呈现的形式所要经历的大致流程如下: 

  • a、根据Uri在已解码的(Bitmap缓存)内存缓存中查找,找到了则返回Bitmap对象;
  • b、如果没找到,则开启后台线程开始后续的工作。
  • c、根据Uri在未解码的内存缓存中查找,若找到了则解码,然后缓存到已解码的内存缓存中,并且返回Bitmap对象。
  • d、如果在未解码的内存缓存中没找到,则根据Uri在磁盘缓存中查找,若找到了则读取数据(byte数组),并缓存到未解码的内存缓存中,解码、然后缓存到已解码的内存缓存中,并且返回Bitmap对象。
  • e、如果在磁盘缓存中没找到,则从网络或者本地加载数据。加载完成后,依次缓存到磁盘缓存未解码的内存缓存中。解码、然后缓存到已解码的内存缓存中,并且返回Bitmap对象。

Drawees 

  Fresco 中设计有一个叫做 Drawees 模块,负责图片的呈现。它由三个元素组成分别是: 
      DraweeView 继承于 View, 负责图片的显示。 
      DraweeHierarchy 用于组织和维护最终绘制和呈现的 Drawable 对象。 
      DraweeController 负责和ImagePipeline的交互,可以创建一个这个类的实例,来实现对所要显示的图片做更多的控制。 
  一般情况下,使用 SimpleDraweeView 即可,你可以配置其XML属性来实现各式各样的展示效果。

a、在图片加载完成前显示占位图; 
b、在图片加载的过程中显示加载进度图; 
c、加载成功后,将占位图或者加载进度图,自动替换为目标图片。 
d、加载失败后,它会显示加载失败的图(若没配置加载失败的图,则显示的是占位图) 
e、加载失败后,若配置过重试图,则会显示重试图,用户点击可以重新去加载图片(默认配置可重试3次) 
f、自定义居中焦点(配合Google提供的服务可以实现人脸识别,经测试国内目前使用不了) 
g、显示圆角图、圆形图和圆圈; 
h、添加覆盖物(图层叠加); 
j、 实现图片的按下效果; 
k、图片的渐进式呈现;(目前只支持Jpeg格式的图片) 
x、当图片不再显示在屏幕上时,它会及时地释放内存和空间占用。

Fresco目前所支持的图片格式 
    静态图:png、jpg、web     动态图:gif、web格式的gif


DEMO:Fresco + RecyclerView三种样式加载本机图片

8.4.2 Fresco    8.4.2 Fresco   8.4.2 Fresco

1、在build.gradle文件中添加依赖

dependencies {
// ...... compile 'com.facebook.fresco:fresco:0.14.1'
compile 'com.facebook.fresco:animated-base-support:0.14.1' // 在 API < 14 上的机器支持 WebP 时
compile 'com.facebook.fresco:animated-gif:0.14.1'       // 支持GIF动图
compile 'com.facebook.fresco:webpsupport:0.14.1'       // 支持WebP
compile 'com.facebook.fresco:animated-webp:0.14.1'      // 支持WebP动图
compile 'com.facebook.fresco:imagepipeline-okhttp3:0.14.1' // 网络实现层想使用okhttp3
}

 2. 初始化Fresco

public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Fresco.initialize(this);
}
}

3. XML文件

1) activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.xmic.view.recycleviewdemo.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>

2)  item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
app:placeholderImage="@mipmap/ic_launcher">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
fresco:fadeDuration="300"
fresco:actualImageScaleType="focusCrop"
fresco:retryImage="@drawable/retry"
fresco:retryImageScaleType="centerCrop"
fresco:progressBarImage="@drawable/retry"
fresco:progressBarImageScaleType="centerInside"
fresco:progressBarAutoRotateInterval="500"
fresco:failureImage="@drawable/fault"
fresco:failureImageScaleType="fitCenter" />
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|bottom"
android:layout_gravity="center"
android:layout_below="@+id/sdv_img"
android:layout_alignParentBottom="true"
android:background="#cccccc"
android:text="Image Titel"/>
</RelativeLayout>

3) item_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_img"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:background="#aaaaaa"
android:layout_marginLeft="10dp"
android:layout_centerVertical="true"
app:placeholderImage="@mipmap/ic_launcher"
fresco:failureImage="@drawable/fault"
fresco:failureImageScaleType="center"
fresco:roundAsCircle="true"
fresco:roundedCornerRadius="180dp"
fresco:actualImageScaleType="focusCrop" />
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="20dp"
android:layout_gravity="center"
android:text="Image Titel"/>
</LinearLayout>

4. Java文件

1) 主界面 MainActivity.java

package com.xmic.view.recycleviewdemo;

import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.RelativeLayout;
import android.widget.Toast; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; public class MainActivity extends AppCompatActivity implements RvAdpter.OnItemClickListener{
private final String TAG = MainActivity.class.getSimpleName();
private final static int SCAN_OK = 1;
private final static int TYPE_WATERFALL = 0;
private final static int TYPE_LISTVIEW = 1;
private final static int TYPE_GRIDVIEW = 2;
private RecyclerView mRecyclerView;
private RvAdpter mAdpter;
private ProgressDialog mProgressDialog;
private List<Product> imageList = new ArrayList<Product>();
RecyclerView.ItemDecoration decorator; private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case SCAN_OK:
showData();
break;
}
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG,"onCreate()");
loadData();
initView();
} private void initView(){
mRecyclerView = (RecyclerView) findViewById(R.id.recyview);
} private void loadData(){
mProgressDialog = ProgressDialog.show(this,null,"Loading...");
new Thread(new Runnable() {
@Override
public void run() {
ArrayList<HashMap<String,String>> pics = getAllPictures(getApplicationContext());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
if(pics != null)
for(int i=0; i< pics.size();i++){
Product item = new Product();
item.setId(pics.get(i).get("image_id"));
item.setLocalThumbPosition(pics.get(i).get("thumbnail_path"));
item.setProductName(pics.get(i).get("image_name"));
item.setLocalPosition(pics.get(i).get("image_path"));
BitmapFactory.decodeFile(item.getLocalPosition(), options);
item.setWidth(options.outWidth);
item.setHeight(options.outHeight);
item.setRatio((float)item.getWidth()/(float)item.getHeight());
imageList.add(item);
}
mHandler.sendEmptyMessage(SCAN_OK);
}
}).start();
} public static ArrayList<HashMap<String,String>> getAllPictures(Context context) {
ArrayList<HashMap<String,String>> picturemaps = new ArrayList<>();
HashMap<String,String> picturemap;
ContentResolver cr = context.getContentResolver();
//先得到缩略图的URL和对应的图片id
Cursor cursor = cr.query(
MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
new String[]{
MediaStore.Images.Thumbnails.IMAGE_ID,
MediaStore.Images.Thumbnails.DATA
},
null,
null,
null);
if (cursor.moveToFirst()) {
do {
picturemap = new HashMap<>();
picturemap.put("image_id",cursor.getInt(0)+"");
picturemap.put("thumbnail_path",cursor.getString(1));
picturemaps.add(picturemap);
} while (cursor.moveToNext());
cursor.close();
}
//再得到正常图片的path
for (int i = 0;i<picturemaps.size();i++) {
picturemap = picturemaps.get(i);
String media_id = picturemap.get("image_id");
cursor = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DISPLAY_NAME
},
MediaStore.Audio.Media._ID + "=" + media_id,
null,
null
);
if (cursor.moveToFirst()) {
do {
picturemap.put("image_path",cursor.getString(0));
picturemap.put("image_name",cursor.getString(1));
picturemaps.set(i,picturemap);
} while (cursor.moveToNext());
cursor.close();
}
}
return picturemaps;
} private void showData(){
Log.i(TAG,"showData()");
mProgressDialog.dismiss();
mAdpter = new RvAdpter(MainActivity.this,imageList);
mAdpter.setOnItemClickListener(this);
showViewStyle(TYPE_WATERFALL);
} private void showViewStyle(int type){
/**
* 用来确定每一个item如何进行排列摆放
* StaggeredGridLayoutManager 瀑布流
* LinearLayoutManager 相当于ListView的效果
* GridLayoutManager 相当于GridView的效果
*/
mAdpter.setType(type);
switch (type){
case TYPE_WATERFALL: //瀑布流
mRecyclerView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT));
mRecyclerView.removeItemDecoration(decorator);
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));
decorator = new DividerGridItemDecoration(this);
mRecyclerView.addItemDecoration(decorator);
break;
case TYPE_LISTVIEW: // ListView
mRecyclerView.removeItemDecoration(decorator);
mRecyclerView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT));
mRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
decorator = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST);
mRecyclerView.addItemDecoration(decorator);
break;
case TYPE_GRIDVIEW: // GridView
mRecyclerView.removeItemDecoration(decorator);
mRecyclerView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT));
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));
decorator = new DividerGridItemDecoration(this);
mRecyclerView.addItemDecoration(decorator);
break;
}
mRecyclerView.setAdapter(mAdpter);
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.menu_add:
mAdpter.addItem();
break;
case R.id.menu_waterfall:
showViewStyle(0);
break;
case R.id.menu_listview:
showViewStyle(1);
break;
case R.id.menu_gridview:
showViewStyle(2);
break;
}
mAdpter.notifyDataSetChanged();
return true;
} @Override
public void onItemClick(int position, Product data) {
Log.e(TAG, "onItemClick: " + position );
Toast.makeText(MainActivity.this,"Click: "+data.getProductName(),Toast.LENGTH_SHORT).show();
} @Override
public void onItemLonkClick(int position) {
Log.e(TAG, "onItemLonkClick: " + position );
Toast.makeText(MainActivity.this,"Remove Item: " + position,Toast.LENGTH_SHORT).show();
mAdpter.removeItem(position);
}
}

2) 适配器 RvAdapter.java

package com.xmic.view.recycleviewdemo;

import android.content.Context;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.request.ImageRequest; import java.util.List; import static com.xmic.view.recycleviewdemo.R.layout.item;
import static com.xmic.view.recycleviewdemo.R.layout.item_list; /**
* Created by neek.chen on 2016/11/15.
*/ public class RvAdpter extends RecyclerView.Adapter<RvAdpter.MyViewHolder> implements View.OnClickListener,View.OnLongClickListener{
private Context context;
private RecyclerView mRecyclerView;//用来计算Child位置
private int type = 0;
private List<Product> list;
private OnItemClickListener onItemClickListener; public interface OnItemClickListener{
void onItemClick(int position, Product data);
void onItemLonkClick(int position);
} public RvAdpter(Context context, List<Product> list){
this.context = context;
this.list = list;
} @Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View contentView;
if(type == 1)
contentView = LayoutInflater.from(context).inflate(item_list,parent,false);
else
contentView = LayoutInflater.from(context).inflate(item,parent,false);
contentView.setOnClickListener(this);
contentView.setOnLongClickListener(this);
return new MyViewHolder(contentView);
} @Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mRecyclerView = recyclerView;
} @Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
if(list == null)
return;
final Product item = list.get(position);
if(type == 1)
holder.title.setText(item.getProductName());
else if(type == 0) {
// holder.itemView
holder.title.setVisibility(View.GONE);
}
else
holder.title.setText(position + "");
String filePath = "file://" + Uri.parse(item.getLocalPosition());
String fileThumbPath = "file://" + Uri.parse(item.getLocalThumbPosition());
DraweeController control = Fresco.newDraweeControllerBuilder()
.setLowResImageRequest(ImageRequest.fromUri(fileThumbPath))
// .setImageRequest(ImageRequest.fromUri(filePath))
.setAutoPlayAnimations(true)
.setOldController( holder.img.getController())
.build();
holder.img.setController(control);
holder.img.setAspectRatio(item.getRatio());
} @Override
public int getItemCount() {
return list == null ? 0 : list.size();
} @Override
public void onClick(View v) {
int childAdapterPosition = mRecyclerView.getChildAdapterPosition(v);
if (childAdapterPosition>= 0 && onItemClickListener!= null)
onItemClickListener.onItemClick(childAdapterPosition,list.get(childAdapterPosition));
} @Override
public boolean onLongClick(View v) {
int childAdapterPosition = mRecyclerView.getChildAdapterPosition(v);
if (onItemClickListener!= null)
onItemClickListener.onItemLonkClick(childAdapterPosition);
return false;
} public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
} public void setType(int type){
this.type = type;
} public class MyViewHolder extends RecyclerView.ViewHolder{
private SimpleDraweeView img;
public TextView title;
public MyViewHolder(View item){
super(item);
img = (SimpleDraweeView)item.findViewById(R.id.sdv_img);
img.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_XY);
title = (TextView)item.findViewById(R.id.tv_title);
}
} public void addItem(){
} public void removeItem(final int positon){
list.remove(positon);
notifyItemRemoved(positon);
} }

3) 分隔线

  采用通用的 DividerGridItemDecoration和 DividerItemDecoration

4) 图片对象Product

   private String id;
private String localPosition;
private String localThumbPosition;
private String productName;
private int width;
private int height;
private float ratio;

Fresco的各种使用场景

 引用:Android图片加载神器之Fresco,基于各种使用场景的讲解

从网络加载一张图片

String url = "http://xxx.jpg";
ImageLoader.loadImage((SimpleDraweeView)findViewById(R.id.sdv_1), url);

 1. 显示一张图片

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_1"
android:layout_width="90dp"
android:layout_height="90dp"
app:actualImageScaleType="centerCrop"/>

2. 显示一张圆形图片

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_2"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginTop="15dp"
app:actualImageScaleType="centerCrop"
app:roundAsCircle="true"/>

 3. 显示一张圆形带边框的图片

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_3"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginTop="15dp"
app:actualImageScaleType="centerCrop"
app:roundAsCircle="true"
app:roundingBorderColor="#fff3cf44"
app:roundingBorderWidth="2dp"/>

4. 显示一张圆角图片

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_4"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginTop="15dp"
app:actualImageScaleType="centerCrop"
app:roundAsCircle="false"
app:roundedCornerRadius="10dp"/>

 5. 显示一张底部是圆角的图片

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_5"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginTop="15dp"
app:actualImageScaleType="centerCrop"
app:roundAsCircle="false"
app:roundedCornerRadius="10dp"
app:roundTopLeft="false"
app:roundTopRight="false"
app:roundBottomLeft="true"
app:roundBottomRight="true"/>

6. 显示一张左上和右下是圆角的图片

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_6"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginTop="15dp"
app:actualImageScaleType="centerCrop"
app:roundAsCircle="false"
app:roundedCornerRadius="10dp"
app:roundTopLeft="true"
app:roundTopRight="false"
app:roundBottomLeft="false"
app:roundBottomRight="true"/>

7. 设置占位图

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_7"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginTop="15dp"
app:actualImageScaleType="centerCrop"
app:placeholderImage="@mipmap/ic_launcher"
app:placeholderImageScaleType="centerCrop" />

8. 带动画的显示(从半透明到不透明)

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_8"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginTop="15dp"
app:actualImageScaleType="centerCrop"
app:fadeDuration=""/>

9. 图层叠加显示

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_10"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginTop="15dp"
app:actualImageScaleType="centerCrop"
app:overlayImage="@mipmap/ic_launcher"/>

10. 其它的属性的配置,比如加载进度、加载失败、重试图

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_11"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginTop="15dp"
app:actualImageScaleType="centerCrop"
app:failureImage="@mipmap/ic_launcher"
app:failureImageScaleType="centerInside"
app:retryImage="@mipmap/ic_launcher"
app:retryImageScaleType="centerCrop"
app:progressBarImage="@mipmap/ic_launcher"
app:progressBarImageScaleType="centerCrop"
app:progressBarAutoRotateInterval=""/>

 11. 从本地文件(比如SDCard上)加载图片

public static void loadFile(final SimpleDraweeView draweeView, String filePath, final int reqWidth, final int reqHeight) {
Uri uri = new Uri.Builder()
.scheme(UriUtil.LOCAL_FILE_SCHEME)
.path(filePath)
.build();
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setRotationOptions(RotationOptions.autoRotate())
.setLocalThumbnailPreviewsEnabled(true)
.setResizeOptions(new ResizeOptions(reqWidth, reqHeight))
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setOldController(draweeView.getController())
.setControllerListener(new BaseControllerListener<ImageInfo>() {
@Override
public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable anim) {
if (imageInfo == null) {
return;
} ViewGroup.LayoutParams vp = draweeView.getLayoutParams();
vp.width = reqWidth;
vp.height = reqHeight;
draweeView.requestLayout();
}
})
.build();
draweeView.setController(controller);
}

调用:

ImageLoader.loadFile((SimpleDraweeView)itemView, photoInfo.thumbnailUrl, , );

 12. 从本地资源(Resources)加载图片

public static void loadDrawable(SimpleDraweeView draweeView, int resId) {
Uri uri = new Uri.Builder()
.scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
.path(String.valueOf(resId))
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(uri)
.setOldController(draweeView.getController())
.build();
draweeView.setController(controller);
}

13. 对图片进行性高斯模糊处理

public static void loadImageBlur(final SimpleDraweeView draweeView, String url) {
loadImage(draweeView, url, new BasePostprocessor() {
@Override
public String getName() {
return "blurPostprocessor";
} @Override
public void process(Bitmap bitmap) {
BitmapBlurHelper.blur(bitmap, 35);
}
});
}

其内部调用的方法

public static void loadImage(SimpleDraweeView simpleDraweeView, String url, BasePostprocessor processor) {
if (TextUtils.isEmpty(url)) {
return;
} Uri uri = Uri.parse(url);
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setRotationOptions(RotationOptions.autoRotate())
.setPostprocessor(processor)
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setOldController(simpleDraweeView.getController())
.build();
simpleDraweeView.setController(controller);
}

调用:

String url = "http://xxx.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
simpleDraweeView.setAspectRatio(0.7f);
ViewGroup.LayoutParams lvp = simpleDraweeView.getLayoutParams();
lvp.width = DensityUtil.getDisplayWidth(this);
ImageLoader.loadImageBlur(simpleDraweeView, url,
DensityUtil.getDisplayWidth(this), DensityUtil.getDisplayHeight(this));

 14. 未知宽高比的情况下显示图片

String url = "http://xx.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ImageLoader.loadImage(simpleDraweeView, url, new SingleImageControllerListener(simpleDraweeView));

 15. 从网络加载并显示gif格式的图片

 String url = "http://xxx.gif";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv);
ImageLoader.loadImage(simpleDraweeView, url);

 16. 加载并显示webp格式的图片

SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ViewGroup.LayoutParams lvp = simpleDraweeView.getLayoutParams();
lvp.width = DensityUtil.getDisplayWidth(this);
simpleDraweeView.setAspectRatio(0.6f); // 设置宽高比 ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi_webp,
DensityUtil.getDisplayWidth(this), DensityUtil.getDisplayHeight(this));

17. 从内存缓存中移除指定图片的缓存

      if (!TextUtils.isEmpty(photoInfo.originalUrl)) {
ImagePipeline imagePipeline = Fresco.getImagePipeline();
Uri uri = Uri.parse(photoInfo.originalUrl);
if (imagePipeline.isInBitmapMemoryCache(uri)) {
imagePipeline.evictFromMemoryCache(uri);
}
}

 18. 从磁盘缓存中移除指定图片的缓存

    ImagePipeline imagePipeline = Fresco.getImagePipeline();
Uri uri = Uri.parse(photoInfo.originalUrl);
// 下面的操作是异步的
if (imagePipeline.isInDiskCacheSync(uri)) {
imagePipeline.evictFromDiskCache(uri);
}

 19、清空磁盘缓存

Fresco.getImagePipeline().clearDiskCaches();

20、清空内存缓存

Fresco.getImagePipeline().clearMemoryCaches();

 21、清空缓存(内存缓存 + 磁盘缓存)

Fresco.getImagePipeline().clearCaches();

 22、在列表视图滚动时,不加载图片,等滚动停止后再开始加载图片,提升列表视图的滚动流畅度。

 // 需要暂停网络请求时调用
public static void pause(){
Fresco.getImagePipeline().pause();
}
// 需要恢复网络请求时调用
public static void resume(){
Fresco.getImagePipeline().resume();
}

23、下载图片存储到指定的路径

/**
* 从网络下载图片
* 1、根据提供的图片URL,获取图片数据流
* 2、将得到的数据流写入指定路径的本地文件
*
* @param url URL
* @param loadFileResult LoadFileResult
*/
public static void downloadImage(Context context, String url, final DownloadImageResult loadFileResult) {
if (TextUtils.isEmpty(url)) {
return;
} 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>>() {
@Override
public void onNewResultImpl(DataSource<CloseableReference<PooledByteBuffer>> dataSource) {
if (!dataSource.isFinished() || loadFileResult == null) {
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);
String photoPath = loadFileResult.getFilePath();
Log.i("ImageLoader", "photoPath = " + photoPath); byte[] data = StreamTool.read(inputStream);
StreamTool.write(photoPath, data);
loadFileResult.onResult(photoPath);
} catch (IOException e) {
loadFileResult.onFail();
e.printStackTrace();
} finally {
imageReference.close();
closeableReference.close();
}
}
} @Override
public void onFailureImpl(DataSource dataSource) {
if (loadFileResult != null) {
loadFileResult.onFail();
} Throwable throwable = dataSource.getFailureCause();
if (throwable != null) {
Log.e("ImageLoader", "onFailureImpl = " + throwable.toString());
}
}
}, Executors.newSingleThreadExecutor());
}

调用

String url = "http://xxx.jpg";
String filePath = "";
ImageLoader.downloadImage(context, url, new DownloadImageResult(filePath) { @Override
public void onResult(String filePath) { } @Override
public void onFail() { }
});

24、不使用SimpleDraweeView组件,但是想使用Fresco去加载图片(两级内存缓存+磁盘缓存要有)并显示到其他组件上(比如显示在TextView的drawableLeft属性上或者显示为View的背景)。

public static void loadTextDrawable(final TextView view, String url, final int direction, final int iconWidth, final int iconHeight) {
ImageLoader.loadImage(view.getContext(), url, new LoadImageResult() {
@Override
public void onResult(Bitmap bitmap) {
Drawable drawable = new BitmapDrawable(view.getContext().getResources(), bitmap);
final int width = DensityUtil.dipToPixels(view.getContext(), iconWidth);
final int height = DensityUtil.dipToPixels(view.getContext(), iconHeight);
drawable.setBounds(0, 0, width, height);
switch (direction) {
case 0:
view.setCompoundDrawables(drawable, null, null, null);
break;
case 1:
view.setCompoundDrawables(null, drawable, null, null);
break;
case 2:
view.setCompoundDrawables(null, null, drawable, null);
break;
case 3:
view.setCompoundDrawables(null, null, null, drawable);
break;
}  
}
});
}