Fresco+RecyclerView初体验

本文介绍了Facebook的图片加载框架Fresco,强调了其内存管理、渐进式加载和动图加载等优势。Fresco由DraweeView、DraweeHierarchy、DraweeController三部分构成,采用MVC架构。文中通过结合RecyclerView展示了Fresco的使用步骤,包括添加依赖、初始化、布局中使用SimpleDraweeView,并探讨了Fresco如何避免内存溢出,特别是其三级缓存策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前网上存在好多图片加载框架,主流的框架有Volley、ImageLoader、fresco、Pisasso、glide,但是fresco无疑是最强大的一个图片加载框架,fresco是facebook推出的一款图片加载框架,它的诸多特性:内存管理、图片加载、以及图片的的渐进式加载和动图加载使得它一经推出收到许多公司的青睐。

     fresco框架主要主要由三部分组成:DraweeViewDraweeHierarchyDraweeController,其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、最后未找到的话就去磁盘中去找,这些图片也是未解码的,找到后需要解码。

最后再没有的话就去网上请求并保存在缓存和磁盘中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值