面试题之---Glide源码解析

(一)Glide和Picasso相比较:

1,Glide可以gif动态图,Picasson不可以

2,Glide默认Bitmap格式是RGB_565,图片质量不如Picasso(ARGB_8888)加载的清晰,但耗内存小.(但Glide也可以准换成ARGB_8888,而且耗内存也相对小些)

2.1,如果你对默认的RGB_565效果还比较满意,可以不做任何事,但是如果你觉得难以接受,可以创建一个新的GlideModule将Bitmap格式转换到ARGB_8888:

    public class GlideConfiguration implements GlideModule {
     
        @Override
        public void applyOptions(Context context, GlideBuilder builder) {
            // Apply options to the builder here.
            builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
        }
     
        @Override
        public void registerComponents(Context context, Glide glide) {
            // register ModelLoaders here.
        }
    }

2.2,同时在AndroidManifest.xml中将GlideModule定义为meta-data

                     android:value="GlideModule"/>

glide和picasso区别

glide,picasso和fresco的区别

3,Picasso的大小大约是118KB,而Glide大约有430KB。

 (Fresco加载大图速度更快,但fresco 最大只支持图片文件大小为 2M 。)

 

(二)基本使用

添加依赖

implementation 'com.github.bumptech.glide:glide:3.7.0'

 Glide.with(this)
     .load(url) //图片地址
     .placeholder(R.drawable.loading)  //占位图
     .error(R.drawable.error) //异常图
     .diskCacheStrategy(DiskCacheStrategy.NONE) //禁用缓存
     .override(100, 100) //固定图片的像素
     .asBitmap()   //强制使用图片,不能加载动图
     .asGif()       //强制使用动图,不能加载图片
     .thumbnail(1f) //缩略图
     .crossFade() //淡入淡出效果
     .bitmapTransform(new CropCircleTransformation(this))  //图片转换
     .into(imageView);

1,图片未加载时的占位图以及图片加载失败的图片展示

Glide.with(this).load(url).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);

 

2,Glide默认是包含淡入淡出动画的时间为300ms(毫秒),我们可以修改这个动画的时间,

Glide.with(this).load(url).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).crossFade(5000).into(iv);

 

3,取消淡入淡出动画

Glide.with(this).load(url).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).dontAnimate().into(iv);

 

4,加载本地图片

// 判断SD卡是否存在,并且是否具有读写权限
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
    Glide.with(this).load(new File(Environment.getExternalStorageDirectory(), "xiaobixiansheng.png")).into(iv);

 

5,加载动态图

Glide.with(this).load(gifUrl).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);

 

6,加载动态图,先判断是否是动态图,不是的话加载错误图片,只需要调用asGif()判断即可

Glide.with(this).load(gifUrl).asGif().placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);

 

7,加载动态图的第一帧的图片,asBitmap()

Glide.with(this).load(gifUrl).asBitmap().placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);

 

8,加载动态图时,使用diskCacheStrategy(),速度回快些,效率高些,因为这是把gif资源缓存到磁盘

Glide.with(this).load(gifUrl).diskCacheStrategy(DiskCacheStrategy.SOURCE).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);

 

9,内存不缓存,磁盘缓存缓存所有图片

Glide.with(this).load(mUrl).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.ALL).into(iv);

设置内存    skipMemoryCache(true).

设置磁盘    diskCacheStrategy (DiskCacheStrategy.ALL)

   磁盘模式

  • DiskCacheStrategy.NONE:表示不缓存任何内容。
  • DiskCacheStrategy.SOURCE:表示只缓存原始图片。
  • DiskCacheStrategy.RESULT:表示只缓存转换过后的图片(默认选项)。
  • DiskCacheStrategy.ALL :表示既缓存原始图片,也缓存转换过后的图片。

10,.内存缓存处理图,磁盘缓存原图

Glide.with(this).load(mUrl).skipMemoryCache(false).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(mIv);

 11,加载正方形图形--override(36,36).centerCrop()

 Glide.with(this).load(R.drawable.shape_rec).apply(new RequestOptions().override(36,36).centerCrop()).into(iv_head);

12,加载圆角图片transform()

(第三方转换框架:https://github.com/wasabeef/glide-transformations

Glide.with(this).load(url).transform(new CornersTransform()).into(iv1);

public  class CornersTransform extends BitmapTransformation {
    private float radius;

    public CornersTransform(Context context) {
        super(context);
        radius = 10;
    }

    public CornersTransform(Context context, float radius) {
        super(context);
        this.radius = radius;
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return cornersCrop(pool, toTransform);
    }

    private Bitmap cornersCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint  = new Paint();
        paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
        canvas.drawRoundRect(rectF, radius, radius, paint);
        return result;
    }

    @Override
    public String getId() {
        return getClass().getName();
    }
}

 13,预加载图片:如果希望提前对图片进行一个预加载,等真正需要加载图片的时候,直接从缓存中读取,不想再等待慢长的网络加载时间了,就使用预加载.(如果使用了preload()方法,最好要将diskCacheStrategy的缓存策略指定成DiskCacheStrategy.SOURCE。因为preload()方法默认是预加载的原始图片大小,而into()方法则默认会根据ImageView控件的大小来动态决定加载图片的大小。因此,如果不将diskCacheStrategy的缓存策略指定成DiskCacheStrategy.SOURCE的话,很容易会造成我们在预加载完成之后再使用into()方法加载图片,却仍然还是要从网络上去请求图片这种现象。)
 

Glide.with(this)
     .load(url)
     .diskCacheStrategy(DiskCacheStrategy.SOURCE)
     .preload();

 实现预加载

14,downloadOnly(),获取缓存文件的地址

public void downloadImage(View view) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                String url = "http://cn.bing.com/az/hprichbg/rb/TOAD_ZH-CN7336795473_1920x1080.jpg";
                final Context context = getApplicationContext();
                FutureTarget target = Glide.with(context).load(url).downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
                final File imageFile = target.get();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, imageFile.getPath(), Toast.LENGTH_LONG).show();
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
}

 

15,滚动加载,不滚动时不加载,提高列表加载数据效率:

Glide.with(context).resumeRequests()

Glide.with(context).pauseRequests()

mRecyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

        if (mBaseContext == null || mBaseContext.isFinishing()) {
            //避免Glide加载图片抛出异常
            return;
        }

        switch (newState) {
            //不滚动,就停止加载
            case RecyclerView.SCROLL_STATE_IDLE:
                Glide.with(mBaseContext).resumeRequests();
                break;
            //滚动,开始加载
            case RecyclerView.SCROLL_STATE_DRAGGING:
            case RecyclerView.SCROLL_STATE_SETTLING:
                Glide.with(mBaseContext).pauseRequests();
                break;
        }
    }
});

 

(三)自定义

   1,    默认情况下,Glide使用的是基于原生HttpURLConnection进行订制的HTTP通讯组件,但是现在大多数的Android开发者都更喜欢使用OkHttp,因此将Glide中的HTTP通讯组件修改成OkHttp的这个需求比较常见

1.1,

public class OkHttpFetcher implements DataFetcher {
    private final OkHttpClient client;
    private final GlideUrl url;
    private InputStream stream;
    private ResponseBody responseBody;
    private volatile boolean isCancelled;

    public OkHttpFetcher(OkHttpClient client, GlideUrl url) {
        this.client = client;
        this.url = url;
    }

    @Override
    public InputStream loadData(Priority priority) throws Exception {
        Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl());
        for (Map.Entry headerEntry : url.getHeaders().entrySet()) {
            String key = headerEntry.getKey();
            requestBuilder.addHeader(key, headerEntry.getValue());
        }
        requestBuilder.addHeader("httplib", "OkHttp");
        Request request = requestBuilder.build();
        if (isCancelled) {
            return null;
        }
        Response response = client.newCall(request).execute();
        responseBody = response.body();
        if (!response.isSuccessful() || responseBody == null) {
            throw new IOException("Request failed with code: " + response.code());
        }
        stream = ContentLengthInputStream.obtain(responseBody.byteStream(), responseBody.contentLength());
        return stream;
    }

    @Override
    public void cleanup() {
        try {
            if (stream != null) {
                stream.close();
            }
            if (responseBody != null) {
                responseBody.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getId() {
        return url.getCacheKey();
    }

    @Override
    public void cancel() {
        isCancelled = true;
    }
}

1.2

public class OkHttpGlideUrlLoader implements ModelLoader {
    private OkHttpClient okHttpClient;

    public static class Factory implements ModelLoaderFactory {
        private OkHttpClient client;

        public Factory() {
        }

        public Factory(OkHttpClient client) {
            this.client = client;
        }

        private synchronized OkHttpClient getOkHttpClient() {
            if (client == null) {
                client = new OkHttpClient();
            }
            return client;
        }

        @Override
        public ModelLoader build(Context context, GenericLoaderFactory factories) {
            return new OkHttpGlideUrlLoader(getOkHttpClient());
        }

        @Override
        public void teardown() {
        }
    }

    public OkHttpGlideUrlLoader(OkHttpClient client) {
        this.okHttpClient = client;
    }

    @Override
    public DataFetcher getResourceFetcher(GlideUrl model, int width, int height) {
        return new OkHttpFetcher(okHttpClient, model);
    }
}

1.3,

public class GlideConfiguration implements GlideModule {
    public static final int DISK_CACHE_SIZE = 500 * 1024 * 1024;//默认是250M,现在改为500M


    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);//Glide默认是RGB-565格式,现在改为ARGB-8888

        //InternalCacheDiskCacheFactory和ExternalCacheDiskCacheFactory的默认硬盘缓存大小都是250M
        //如果你的应用缓存的图片总大小超出了250M,那么Glide就会按照DiskLruCache算法的原则来清理缓存的图片。
        //builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));//缓存到sd卡上
        builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, DISK_CACHE_SIZE));
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
        glide.register(GlideUrl.class, InputStream.class,new OkHttpGlideUrlLoader.Factory());
    }
    
}

1.4,在清单文件设置meta


(四)封装

1.封装

public class GlideUtil {
    public static void load(Context context, String url, ImageView imageView, RequestOptions options) {
        Glide.with(context).load(url).apply(options).into(imageView);
    }
}

2,展位图,异常图

RequestOptions options = new RequestOptions()
        .placeholder(R.drawable.ic_launcher_background)
        .error(R.drawable.error)
        .diskCacheStrategy(DiskCacheStrategy.NONE);
        .override(200, 100)//指定图片大小
        .skipMemoryCache(true)//取消内存
Glide.with(this).load(url).apply(options).into(imageView);

(五)源码解析

1,Glide采用的是三级缓存,内存–>磁盘–>网络\

Glide的缓存功能,大部分都是在load()方法中进行的
1.1,缓存的作用:

 A:内存缓存的主要作用 :    是防止应用重复将图片数据读取到内存当中,

 B:磁盘缓存的主要作用 :   是防止应用重复从网络或其他地方重复下载和读取数据。

 C:Glide内存缓存的实现自然也是使用的LruCache算法。并且还结合了一种弱引用的机制,共同完成了内存缓存功能

1.2,内存缓存,内存缓存最大空间(maxSize)=每个进程可用的最大内存 * 0.4(低配手机的话是: 每个进程可用的最大内存 * 0.33)

//代码在MemorySizeCalculator
final int maxSize = getMaxSize(activityManager);

private static int getMaxSize(ActivityManager activityManager) {
    //每个进程可用的最大内存
    
final int memoryClassBytes = activityManager.getMemoryClass() * 1024 * 1024;

    //判断是否低配手机
    
final boolean isLowMemoryDevice = isLowMemoryDevice(activityManager);

    return Math.round(memoryClassBytes
            * (isLowMemoryDevice ? LOW_MEMORY_MAX_SIZE_MULTIPLIER : MAX_SIZE_MULTIPLIER));
}

 

1.3磁盘缓存的大小是250m

 

2,Glide的对象,是通过调用get()获取,采用的是单利双重锁模式,保证了Glide对象的唯一性

private static volatile Glide glide;
public static Glide get(Context context) {

    if (glide == null) {

        //同步Glide
        synchronized (Glide.class) {
            if (glide == null) {
                Context applicationContext = context.getApplicationContext();

                //解析清单文件配置的自定义GlideModule的metadata标签,返回一个GlideModule集合
         List modules = new ManifestParser(applicationContext).parse();

                GlideBuilder builder = new GlideBuilder(applicationContext);

                //循环集合,执行GlideModule 实现类中的方法
         for (GlideModule module : modules) {
                    module.applyOptions(applicationContext, builder);
                }
                glide = builder.createGlide();
                for (GlideModule module : modules) {
                    //注册组件

           module.registerComponents(applicationContext, glide);
                }
            }
        }
    }

    return glide;
}

 

 

 

3,Glide.with()

     With方法有5个重载的构造方法,运行你在activity,frgament或者其他地方使用.得到一个RequestManager对象,RequestManager实现了LifeCycleListener接口,绑定Activity/Fragment生命周期,对请求进行暂停,恢复,清除操作.

下面是5个构造方法

//RequestManager实现了LifeCycleListener接口
public static RequestManager with(Context context) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(context);
}

public static RequestManager with(Activity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}



public static RequestManager with(FragmentActivity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}



@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(fragment);
}

//V4包的fragment
public static RequestManager with(Fragment fragment) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(fragment);
}

 

 

 

3.1RequestManage对象源码

public class RequestManager implements LifecycleListener {
    private final Context context;
    private final Lifecycle lifecycle;
    private final RequestManagerTreeNode treeNode;
    private final RequestTracker requestTracker;
    private final Glide glide;

    public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
        this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
    }

    RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
                   RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
        this.context = context.getApplicationContext();
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        this.requestTracker = requestTracker;

        //通过Glide的静态方法获取实例对象,Glide是通过单利创建的
    this.glide = Glide.get(context);
        this.optionsApplier = new OptionsApplier();

 

 

 

 

3.2如果是在子线程调用with(),或者上下文传入的是Application的上下文,那生命周期就与Application的生命周期同步

public class RequestManagerRetriever implements Handler.Callback{

    private RequestManager getApplicationManager(Context context) {
        if (applicationManager == null) {
            synchronized (this) {
                if (applicationManager == null) {
                    applicationManager = new RequestManager(context.getApplicationContext(),
                            new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                }
            }
        }

        return applicationManager;
    }

 

 

 

4,load(url)

Glide的缓存功能,大部分都是在load()方法中进行的

load()也有很多重载的方法,它可以加载网络图片,本地图片,gif(动态图)图,Uri,File,

public DrawableTypeRequest load(String string) {
    return (DrawableTypeRequest) fromString().load(string);
}

//加载Uri
public DrawableTypeRequest load(Uri uri) {
    return (DrawableTypeRequest) fromUri().load(uri);
}

//加载File
public DrawableTypeRequest load(File file) {
    return (DrawableTypeRequest) fromFile().load(file);
}



//直接加载图片资源id,   R.mipmap.ic_launcher
public DrawableTypeRequest load(Integer resourceId) {
    return (DrawableTypeRequest) fromResource().load(resourceId);
}



//加载URL
@Deprecated
public DrawableTypeRequest load(URL url) {
    return (DrawableTypeRequest) fromUrl().load(url);
}

 

 

 

5,Glide的into()方法

 

public Target into(ImageView view) {
    Util.assertMainThread();
    if (view == null) {
        throw new IllegalArgumentException("You must pass in a non null View");
    }

    if (!isTransformationSet && view.getScaleType() != null) {
        switch (view.getScaleType()) {
            case CENTER_CROP:
                applyCenterCrop();
                break;
            case FIT_CENTER:
            case FIT_START:
            case FIT_END:
                applyFitCenter();
                break;
            //$CASES-OMITTED$
            default:
                // Do nothing.
        }
    }

    return into(glide.buildImageViewTarget(view, transcodeClass));
}

最终调用的into方法

//Target我们可以理解成View,只是Glide对我们的View做了一层封装。
public > Y into(Y target) {
    //判断是否在主线程,(UI界面更新只能在主线程),不在主线程就报异常
    Util.assertMainThread();
    if (target == null) {
        throw new IllegalArgumentException("You must pass in a non null Target");
    }
    if (!isModelSet) {
        throw new IllegalArgumentException("You must first set a model (try #load())");
    }
    //获取request对象
    Request previous = target.getRequest();
    //requestTracker是请求跟踪类对象,主要管理请求的发起,暂停,清除
    if (previous != null) {
        previous.clear();
        requestTracker.removeRequest(previous);
        previous.recycle();
    }
    //创建request对象
    Request request = buildRequest(target);
    target.setRequest(request);

    //将target加入lifecycle,绑定生命周期
    lifecycle.addListener(target);

    //执行请求
    requestTracker.runRequest(request);

    return target;
}

借鉴:

Glide最全讲解: https://blog.csdn.net/sinyu890807/column/info/15318

 

Glide使用详细介绍:https://blog.csdn.net/bzlj2912009596/article/details/81702367

Android图片加载框架最全解析(一),Glide的基本用法 :https://blog.csdn.net/guolin_blog/article/details/53759439

Glide-源码详解  https://blog.csdn.net/yulyu/article/details/60331803

Glide-内存缓存与磁盘缓存  https://blog.csdn.net/yulyu/article/details/55096713

Google推荐——Glide使用详解  https://www.jianshu.com/p/7ce7b02988a4

 

 

你可能感兴趣的:(框架源码解析)