目前网上存在好多图片加载框架,主流的框架有Volley、ImageLoader、fresco、Pisasso、glide,但是fresco无疑是最强大的一个图片加载框架,fresco是facebook推出的一款图片加载框架,它的诸多特性:内存管理、图片加载、以及图片的的渐进式加载和动图加载使得它一经推出收到许多公司的青睐。
fresco框架主要主要由三部分组成:DraweeView、DraweeHierarchy、DraweeController,其中DraweeController通过管理ImagePipeLine实现对于图片的管理,ImagePipeLine采用三级缓存,二级内存缓存、一级磁盘缓存,DraweeHierarchy主要用来储存一些视图数据,DraweeController内部通过DraweeHolder用来组织管理DraweeHierarchy与DraweeView。
fresco采用MVC架构将三部分组织起来:
Model: DraweeHierarchy用于组织和维护最终绘制和呈现的 Drawable对象
View: DraweeView用于显示视图
Controller:
DraweeController负责与Imagepipeline交互
接下来我先结合RecyclerView给大家简单介绍下fresco的使用:
首先我们在项目Bulder.gradle中引入fresco的包
接下来就上代码了:
首先初始化fresco,这个过程在Application中初始化,fresco也提供了两种初始化的方法我们可以自由选择,其中双参属的可以用来配置ImagePipeLine的参数。
initialize(Context context)
initialize(Context context, ImagePipelineConfig imagePipelineConfig)
然后在布局中添加SimpleDraweeView组件:
<span style="font-size:18px;">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="100dp"
android:orientation="horizontal">
<com.facebook.drawee.view.SimpleDraweeView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@mipmap/ic_launcher"
android:id="@+id/item_simpledraweeview">
</com.facebook.drawee.view.SimpleDraweeView>
<TextView
android:id="@+id/text_show"
android:textSize="16sp"
android:layout_marginLeft="10dp"
android:layout_width="fill_parent"
android:gravity="left|center_vertical"
android:textColor="#000000"
android:layout_height="100dp" />
</LinearLayout></span>
Activity页面:
<pre name="code" class="java">package com.example.pan.frescopro;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
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.View;
import com.facebook.drawee.view.SimpleDraweeView;
import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.api.GoogleApiClient;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
public String url1 = "http://www.xywangpan.cn/image/alone.png";
public String url2 = "http://www.xywangpan.cn/image/biancheng.png";
public String url3 = "http://www.xywangpan.cn/image/hongloumeng.png";
public String url4 = "http://www.xywangpan.cn/image/java.png";
public String url5 = "http://www.xywangpan.cn/image/leiyu.png";
public String url6 = "http://www.xywangpan.cn/image/pingfandeshijie.png";
public String url7 = "http://www.xywangpan.cn/image/suanfa.png";
public String url8 = "http://www.xywangpan.cn/image/yigerendechaosheng.png";
SimpleDraweeView simpleDraweeView;
RecyclerView mRecyclerView;
List<BookBean> datas = new ArrayList<BookBean>();
RecyclerViewAdapter adapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
public void initData() {
for (int i=0;i<10000;i++) {
datas.add(new BookBean("愿有人陪你颠破流离", url1));
datas.add(new BookBean("一个人的朝圣", url8));
datas.add(new BookBean("边城", url2));
datas.add(new BookBean("红楼梦", url3));
datas.add(new BookBean("JAVA", url4));
datas.add(new BookBean("雷雨", url5));
datas.add(new BookBean("平凡的世界", url6));
datas.add(new BookBean("算法", url7));
}
}
public void initView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
adapter = new RecyclerViewAdapter(datas, getApplicationContext());
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.addItemDecoration(new DividerItemDecoration(this,
DividerItemDecoration.VERTICAL_LIST));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(adapter);
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onStop() {
super.onStop();
}
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if ((orientation != HORIZONTAL_LIST)) {
if ((orientation != VERTICAL_LIST)) {
throw new IllegalArgumentException("invalid orientation");
}
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
RecyclerView v = new RecyclerView(parent.getContext());
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
}
RecyclerViewAdapter
RecylerViewAdapter.java
<pre name="code" class="java">package com.example.pan.frescopro;
import android.content.Context;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
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.core.ImagePipeline;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import java.util.List;
/**
* Created by pan on 2016/8/2.
*/
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
List<BookBean> strs;
Context context;
public RecyclerViewAdapter(List<BookBean> strs, Context context) {
this.strs = strs;
this.context = context;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.fresco_item, parent, false);
return new ViewHolder(v);
}
Uri uri;
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.mtextshow.setText(strs.get(position).getName());
Log.d("Tag", strs.get(position).getUrl().toString());
System.out.println("--------" + strs.get(position).getUrl().toString());
uri = Uri.parse(strs.get(position).getUrl());
holder.msimpleDraweeView.setController(controller);
holder.msimpleDraweeView.setImageURI(uri);//通过调用simpleDraeeView的setImageUrI(UrI)方法设置图片
}
@Override
public int getItemCount() {
return strs.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView mtextshow;
SimpleDraweeView msimpleDraweeView;
public ViewHolder(View init) {
super(init);
mtextshow = (TextView) init.findViewById(R.id.text_show);
msimpleDraweeView = (SimpleDraweeView) init.findViewById(R.id.item_simpledraweeview);
//设置宽高比例
msimpleDraweeView.setAspectRatio(1f);
//设置对其方式
msimpleDraweeView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER);
}
}
@Override
public int getItemViewType(int position) {
return strs.get(position).getType();
}
}
运行效果如下(加载效果还是很流畅的):
那么大家有没有想过什么保证了fresco加载上千张图片而不溢出呢?大家是不是想到了ImageLoader的缓存机制了,ImageLoader里面使用Lrucahe通过LinkHashMap实现最近最久算法,保证在内存超出限定值是及时的移除最久未使用的Bitmap,但是fresco又是怎么实现的呢?
其实在Android5.0之前fresco将Bitmap存于ashmem这块内存中而不是存在于堆中,由于在堆中会频繁的触发GC,这样当内存不够是会清除一些数据,但是ashmen这块内存是归Linux内核去管理,它内部有一个引用计数器,他会在内存不够时,优先移除引用数为0的Bitmap,这样就保证了内存不会被溢出,
它内部采用三级缓存策略:
1、首先会在解码后的Bitmap中去找,找到后就直接使用。
2、然后没有在缓存中找到就在未解码的缓存中去找,找到后就去解码使用。
3、最后未找到的话就去磁盘中去找,这些图片也是未解码的,找到后需要解码。
最后再没有的话就去网上请求并保存在缓存和磁盘中。