Glide日常使用以及重难点解读
Posted Jason_Lee155
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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:
<meta-data
android:name="com.inthecheesefactory.lab.glidepicasso.GlideConfiguration"
android:value="GlideModule"/>
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);
- 图片未加载时的占位图以及图片加载失败的图片展示
Glide.with(this).load(url).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);
- Glide默认是包含淡入淡出动画的时间为300ms(毫秒),我们可以修改这个动画的时间,
Glide.with(this).load(url).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).crossFade(5000).into(iv);
- 取消淡入淡出动画
Glide.with(this).load(url).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).dontAnimate().into(iv);
- 加载本地图片
// 判断SD卡是否存在,并且是否具有读写权限
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
Glide.with(this).load(new File(Environment.getExternalStorageDirectory(), "meinv.png")).into(iv);
- 加载动态图
Glide.with(this).load(gifUrl).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);
- 加载动态图,先判断是否是动态图,不是的话加载错误图片,只需要调用asGif()判断即可
Glide.with(this).load(gifUrl).asGif().placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);
- 加载动态图的第一帧的图片,asBitmap()
Glide.with(this).load(gifUrl).asBitmap().placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);
- 加载动态图时,使用diskCacheStrategy(),速度回快些,效率高些,因为这是把gif资源缓存到磁盘
Glide.with(this).load(gifUrl).diskCacheStrategy(DiskCacheStrategy.SOURCE).placeholder(R.mipmap.place).error(R.mipmap.icon_photo_error).into(iv);
- 内存不缓存,磁盘缓存缓存所有图片
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 :表示既缓存原始图片,也缓存转换过后的图片。
- 内存缓存处理图,磁盘缓存原图
Glide.with(this).load(mUrl).skipMemoryCache(false).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(mIv);
- 加载正方形图形--override(36,36).centerCrop()
Glide.with(this).load(R.drawable.shape_rec).apply(new RequestOptions().override(36,36).centerCrop()).into(iv_head);
- 加载圆角图片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();
}
}
- 预加载图片:如果希望提前对图片进行一个预加载,等真正需要加载图片的时候,直接从缓存中读取,不想再等待慢长的网络加载时间了,就使用预加载.
(如果使用了preload()方法,最好要将diskCacheStrategy的缓存策略指定成DiskCacheStrategy.SOURCE。因为preload()方法默认是预加载的原始图片大小,而into()方法则默认会根据ImageView控件的大小来动态决定加载图片的大小。因此,如果不将diskCacheStrategy的缓存策略指定成DiskCacheStrategy.SOURCE的话,很容易会造成我们在预加载完成之后再使用into()方法加载图片,却仍然还是要从网络上去请求图片这种现象。)
// 实现预加载
Glide.with(this)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.preload();
- 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<File> 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();
}
- 滚动加载,不滚动时不加载,提高列表加载数据效率:
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的这个需求如下:
public class OkHttpFetcher implements DataFetcher<InputStream> {
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<String, String> 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;
}
}
public class OkHttpGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
private OkHttpClient okHttpClient;
public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
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<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
return new OkHttpGlideUrlLoader(getOkHttpClient());
}
@Override
public void teardown() {
}
}
public OkHttpGlideUrlLoader(OkHttpClient client) {
this.okHttpClient = client;
}
@Override
public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
return new OkHttpFetcher(okHttpClient, model);
}
}
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());
}
}
// 在清单文件设置meta:
<meta-data android:name="cn.xmqy.hoyouchang.util.GlideConfiguration"
android:value="GlideModule"/>
封装
public class GlideUtil {
public static void load(Context context, String url, ImageView imageView, RequestOptions options) {
Glide.with(context).load(url).apply(options).into(imageView);
}
}
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()方法中进行的
缓存的作用:
- 内存缓存的主要作用 : 是防止应用重复将图片数据读取到内存当中,
- 磁盘缓存的主要作用 : 是防止应用重复从网络或其他地方重复下载和读取数据。
- Glide内存缓存的实现自然也是使用的LruCache算法。并且还结合了一种弱引用的机制,共同完成了内存缓存功能
内存缓存最大空间(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));
}
磁盘缓存的大小是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<GlideModule> 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);
}
RequestManage对象源码:
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();
如果是在子线程调用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<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
}
//加载Uri
public DrawableTypeRequest<Uri> load(Uri uri) {
return (DrawableTypeRequest<Uri>) fromUri().load(uri);
}
//加载File
public DrawableTypeRequest<File> load(File file) {
return (DrawableTypeRequest<File>) fromFile().load(file);
}
//直接加载图片资源id, R.mipmap.ic_launcher
public DrawableTypeRequest<Integer> load(Integer resourceId) {
return (DrawableTypeRequest<Integer>) fromResource().load(resourceId);
}
//加载URL
@Deprecated
public DrawableTypeRequest<URL> load(URL url) {
return (DrawableTypeRequest<URL>) fromUrl().load(url);
}
5. Glide的into()方法
public Target<TranscodeType> 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));
}
//Target我们可以理解成View,只是Glide对我们的View做了一层封装。
public <Y extends Target<TranscodeType>> 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日常使用以及重难点解读的主要内容,如果未能解决你的问题,请参考以下文章