Glide几个基本概念
1.Model:表示数据来源,可以是url,本地文件,资源id等
2.Data:从数据源获取Model后,加工成原始数据,一般就是inputstream,glide称之为Data;而从数据源中获取原始数据的功能叫做ModelLoader。
3.Resource:对刚获取的原始数据解码,例如将inputstream解码成bitmap,解码之后的资源称之为Resource,而负责解码功能的角色ResourceDecode
4.TransformedResource:Resource进行变化,例如图片进行裁剪,用ResourceTransform这个功能转换,转换后的资源称为TransformedResource
5.TranscodedResource:转码;glide支持gif,但是解码后的bitmap跟gifDrawable类型不是统一,为了类型统一把bitmap转换为glideBitmapDrawable,负责转码角色叫Transcode,转码完成后的角色叫做TranscodedResource
6.Target:最终将图片显示到目标上imageview,将显示的目标封装成Target
glide流程.png
Glide使用方法
Glide.with(context).load(url).into(imageview);//简单使用
Glide.with(activity)
.load(url)
.placeholder(R.drawable.block_canary_icon)
.error(R.drawable.block_canary_icon)
.override(300,300)//指定图片的尺寸
.fitCenter()
.centerCrop()
.skipMemoryCache(true)//跳过内存缓存
.crossFade(1000)//设置渐变式显示的时间
.diskCacheStrategy(DiskCacheStrategy.NONE)//跳过磁盘缓存
.diskCacheStrategy(DiskCacheStrategy.SOURCE)//仅仅只缓存原来的全分辨率图像
.diskCacheStrategy(DiskCacheStrategy.RESULT)//仅仅缓存最终的图像
.diskCacheStrategy(DiskCacheStrategy.ALL)//缓存所有版本的图像
.priority(Priority.HIGH)//指定优先级,作为一个准则,并尽可能的处理这些请求
.into(iv);
with方法
按最简单的使用方式查看流程
Glide.with(context).load(url).into(imageview);
with方法可以传不同类型的参数,activity,fragment等,为了就是让Glide的生命周期我们安卓组件相挂钩。大致可以分两种,一种是Application,一种是非Application
public static RequestManager with(Context context) {
//RequestManagerRetriever就是获取RequestManager的,而RequestManager可以理解为我们处理图片加载请求的管理者
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
public RequestManager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
//这是Application参数
return getApplicationManager(context);
}
//单例创建,Glide不需要做特殊处理,不需要跟生命周期挂钩
private RequestManager getApplicationManager(Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
applicationManager = new RequestManager(context.getApplicationContext(),
new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
}
}
}
return applicationManager;
}
application参数比较简单,下面看下非application参数,例如Activity
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RequestManager get(Activity activity) {
//不在主线程或者sdk小于3.0直接走application流程
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
//创建空fragement,添加没有页面的Fragment用于监听activity的生命周期
RequestManagerFragment current = getRequestManagerFragment(fm);
//RequestManager 不仅仅能管理请求,也能实现界面生命周期的监听
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
//current.getLifecycle()这个跟fragement的生命周期绑定
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
//将空的RequestManagerFragment 跟requestManager绑定(一一对应),监听activity生命周期来管理图片加载
current.setRequestManager(requestManager);
}
return requestManager;
}
//通过lifecycle绑定生命周期
public class RequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
}
总结:1.获取RequestManager 来管理我们的请求
2.Glide使用RequestManagerFragment 这个无UI的fragment,让它绑定Activity,由它监听生命周期
3.RequestManager通过RequestManagerFragment中的lifecycle监听生命周期
load方法
load方法在RequestManager中
public DrawableTypeRequest<String> load(String string) {
//DrawableTypeRequest是加载图片的所有request请求
return (DrawableTypeRequest<String>) fromString().load(string);
}
//继承DrawableRequestBuilder,就是builder模式
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
public BitmapTypeRequest<ModelType> asBitmap() {
return optionsApplier.apply(new BitmapTypeRequest<ModelType>(this, streamModelLoader,
fileDescriptorModelLoader, optionsApplier));
}
public GifTypeRequest<ModelType> asGif() {
return optionsApplier.apply(new GifTypeRequest<ModelType>(this, streamModelLoader, optionsApplier));
}
}
public class DrawableRequestBuilder<ModelType>
extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
implements BitmapOptions, DrawableOptions {
//有很多的方法,都是builder模式中的,例如fitCenter(),centerCrop(),into()等
}
//Glide配置参数的最终类
public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable {
// 跟踪图片请求的周期,还可以取消重启一些失败的图片请求
protected final RequestTracker requestTracker;
private int placeholderId;
private int errorId;
.......
}
看下创建DrawableTypeRequest的fromString()方法
public DrawableTypeRequest<String> fromString() {
return loadGeneric(String.class);
}
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
//创建两个ModelLoader,用于从数据源加载数据
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
return optionsApplier.apply(
new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}
总结:load方法做的也是一些初始化工作,获取一个DrawableTypeRequest对象,通过这个对象就可以获取图片请求的request,从而进行我们实际的图片加载请求
into方法
真正的逻辑在GenericRequestBuilder类中实现.
1.封装 target
首先看下target类,我们穿进去的imageview等会封装成target
public interface Target<R> extends LifecycleListener {
void onLoadStarted(Drawable placeholder);
void onLoadFailed(Exception e, Drawable errorDrawable);
void onResourceReady(R resource, GlideAnimation<? super R> glideAnimation);
void onLoadCleared(Drawable placeholder);
void getSize(SizeReadyCallback cb);
void setRequest(Request request);
Request getRequest();
}
//这个跟我们的activity等的生命周期绑定
public interface LifecycleListener {
void onStart();
void onStop();
void onDestroy();
}
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.
}
}
//buildImageViewTarget创建target对象,如果调用了asBitmap返回BitmapImageViewTarget,没有可能返回GlideDrawableImageViewTarget
return into(glide.buildImageViewTarget(view, transcodeClass));
}
2.request建立和begin方法
通过上面的into方法,我们封装了target并且调用下面的into方法,这个方法主要是做两个步骤
1.创建我们加载图片的request,在创建这个request之前需要对我们旧的target绑定的request删除,再新建一个target绑定到request
2.发送request,交给我们的requestTracker(request的管理和跟踪器 );执行request.begin,重点是onSizeReady方法,里面开始图片的加载
public <Y extends Target<TranscodeType>> Y into(Y target) {
//一定要在主线程中操作,否则抛出异常
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())");
}
//获取target当前绑定的request对象,也就是旧的request
Request previous = target.getRequest();
if (previous != null) {
//资源回收,设置状态等
previous.clear();
//将glide监听request暂停
requestTracker.removeRequest(previous);
//成员变量赋值为null,REQUEST_POOL.offer(this),request不用后将它放到请求池供复用
previous.recycle();
}
// 创建需要的request对象,以前listview中item错位问题,给我们的view setTag来将我们的
//view跟图片绑定;Glide解决方案一样,通过View settag方法将imageview跟图片的request
//请求绑定在一起, 这样很容易判断当前Imageview是否复用,复用之前我们会先取消request请
//求,从而避免图片错位
(1) Request request = buildRequest(target);
//把request跟target绑定,通过view.setTag(request)
target.setRequest(request);
lifecycle.addListener(target);
(2) requestTracker.runRequest(request);
return target;
}
(1).Request request = buildRequest(target);加下来看下如果创建request;主要也是一些参数的赋值
private Request buildRequest(Target<TranscodeType> target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
......//跟缩略图有关的一些分支,略
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
return GenericRequest.obtain(......//好多好多参数);
}
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(....){
//从线程池中获取一个request,能复用则复用
GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
if (request == null) {
request = new GenericRequest<A, T, Z, R>();
}
// 一些初始化操作
request.init(......);
}
(2) requestTracker.runRequest(request);接下来看下这个方法
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
private final List<Request> pendingRequests = new ArrayList<Request>();
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
//没有正在请求的request的话
request.begin();
} else {
//挂起
pendingRequests.add(request);
}
}
先看下 request.begin();
@Override
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
//是否设定 .override(300,300)
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
//获取size,最终还是会回调onSizeReady;如果获取size失败,则说明view还没绘制完,调用ViewTree监听
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
//获取占位图
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
3.Loadprovider
由上面几步,到了request.begin方法,里面最重要的是最终会到onsizeReady方法,看下这个方法是如何实现的:
1).通过LoadProvider去获取ModelLoader和ResourceTranscoder(原始数据解码的对象)
2).根据ModelLoader去获取DataFetcher(将Data原始数据转换成我们能用的不同图片类型)
3).最后将这些参数传到engine,去做实际的图片加载
4.engine.load()
Engine类负责开启图片加载,同时还可以管理正在使用和处于缓存状态的图片
内存缓存:(1).LruCache:最近所使用的对象的强引用存于LinkedHashMap中,并且把最近最少使用的对象在缓存池达到预设值前从内存中移除;(2).弱引用。
加载图片缓存有如下几个步骤:
(1).从内存缓存中读取我们加载的图片loadFromCache(),如果存在直接回调onResourceReady()
(2).如果获取失败,再调用loadFromActiveResources(),表明在缓存中没有我们再看下正在使用的图片中是否存在(Map<Key, WeakReference<EngineResource<?>>> activeResources 中获取);如果存在,再回调
(3).都没有再启Runnable从磁盘或者网络中获取
(1).如果命中缓存,将缓存从memerycache中移除,然后放到activeResources 中,返回engineResource中++acquired
(2).如果缓存失效,则尝试从activeResources 获取
ps:engineResource中acquired为0时会从activeResources 清除,然后放到memerycache中
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
//加载图片的唯一标识,例如如果是网络图片,可能是url地址
final String id = fetcher.getId();
//Glide缓存的key
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
//从缓存中获取图片;内部通过LruCache算法
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
//以EngineResource弱引用为value,也就是一个hashmap
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
//通过handler发送一条消息,然后执行逻辑切回主线程
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
Glide相关问题
1.Bitmap
(1).为什么Bitmap会导致OOM
a.使用ListView,GridView:没有合理的处理缓存,大量加载Bitmap(可以使用三级缓存,设置Listview的滑动监听事件)。
b.图片分辨率高,消耗的内存大,图片Bitmap所占用的内存=图片长度图片宽度一个像素占用的字节数;
c.VM值上线,在每个rom都会设置每个应用的堆内存上限值;dalvik.vm.heapgrowlimit
(2).Bitmap的4种优化策略
a.对图片质量进行压缩
bitmap.compress(Bitmap.CompressFormat.JPEG,100,outputstream);//100 代表不压缩
b.图片按比例进行压缩
BitmapFactory.Options.inJustDecodeBounds = true(只获取宽高而不分配内存)
BitmapFactory.Options.inSampleSize(缩放比)
c.关于bitmap的recycle方法(争议)
d.捕获异常 OutofMemoryError
2.三级缓存/LruCache算法
三级缓存:内存-本地-网络;
内存缓存:LRU缓存算法,当我们缓存满的时候会优先淘汰那些最近最不经常使用的缓存对象
内部用LinkedHashMap
网友评论