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三种样式加载本机图片
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="3000"/>
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="5000"/>
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, 120, 120);
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; } } }); }