Glide4.5分析
Glide的基本流程介绍
常见调用方式 Glide.with(context).load((T)url).into(imageView); 这里调用了三个方法
-
- With
-
- Load
-
- Into
With方法:
首先进入Glide类中调用这个方法
1public static RequestManager with(@NonNull Context context) { 2 return getRetriever(context).get(context); 3} 4 5/** 6这里get方法中传进去一个context然后闲进去非空判断 7再判断是否再主线程中其次再判断context不能等于全局上下文 8 这里说下为什么,如果是全局上下文不利于资源的销毁 9然后再走,判断上下午是哪个类型,最后相应的返回。 10*/ 11@NonNull 12public RequestManager get(@NonNull Context context) { 13 if (context == null) { 14 throw new IllegalArgumentException("You cannot start a load on a null Context"); 15 } else if (Util.isOnMainThread() && !(context instanceof Application)) { 16 if (context instanceof FragmentActivity) { 17 return get((FragmentActivity) context); 18 } else if (context instanceof Activity) { 19 return get((Activity) context); 20 } else if (context instanceof ContextWrapper) { 21 return get(((ContextWrapper) context).getBaseContext()); 22 } 23 } 24 25 return getApplicationManager(context); 26} 27 28/** 29如果上面的context是全局上下文,则会调用getApplicationManager方法,构造一个ApplicationManager对象返回。 30ApplicationLifecycle是生命周期接口 31EmptyRequestManagerTreeNode是树节点接口 32public Set<RequestManager> getDescendants() { 33 return Collections.emptySet(); 34} 35看里面的方法应该是保存了许多RequestManager节点,负责取出 36构建完毕返回 37 38*/ 39private RequestManager getApplicationManager(@NonNull Context context) { 40 // Either an application context or we're on a background thread. 41 if (applicationManager == null) { 42 synchronized (this) { 43 if (applicationManager == null) { 44 // Normally pause/resume is taken care of by the fragment we add to the fragment or 45 // activity. However, in this case since the manager attached to the application will not 46 // receive lifecycle events, we must force the manager to start resumed using 47 // ApplicationLifecycle. 48 49 // TODO(b/27524013): Factor out this Glide.get() call. 50 Glide glide = Glide.get(context.getApplicationContext()); 51 applicationManager = 52 factory.build( 53 glide, 54 new ApplicationLifecycle(), 55 new EmptyRequestManagerTreeNode(), 56 context.getApplicationContext()); 57 } 58 } 59 } 60 61 return applicationManager; 62}
这里又用到了RequestManagerRetriever类。 看这个类的注释 *创建新{@link com.bumptech.glide的静态方法集合。RequestManager}年代或 *从活动和片段中检索已有的。 应该是个工具类。
最后得到一个RequestManager对象
1if (context instanceof FragmentActivity) { 2 return get((FragmentActivity) context); 3} else if (context instanceof Activity) { 4 return get((Activity) context); 5} else if (context instanceof ContextWrapper) { 6 return get(((ContextWrapper) context).getBaseContext()); 7} 8看上面的代码,对不同的activity进行不同的处理, 9@NonNull 10public RequestManager get(@NonNull FragmentActivity activity) { 11 if (Util.isOnBackgroundThread()) { 12 return get(activity.getApplicationContext()); 13 } else { 14 assertNotDestroyed(activity); 15 FragmentManager fm = activity.getSupportFragmentManager(); 16 return supportFragmentGet(activity, fm, null /*parentHint*/); 17 } 18} 19@NonNull 20public RequestManager get(@NonNull Fragment fragment) { 21 Preconditions.checkNotNull(fragment.getActivity(), 22 "You cannot start a load on a fragment before it is attached or after it is destroyed"); 23 if (Util.isOnBackgroundThread()) { 24 return get(fragment.getActivity().getApplicationContext()); 25 } else { 26 FragmentManager fm = fragment.getChildFragmentManager(); 27 return supportFragmentGet(fragment.getActivity(), fm, fragment); 28 } 29} 30 31@NonNull 32public RequestManager get(@NonNull Activity activity) { 33 if (Util.isOnBackgroundThread()) { 34 return get(activity.getApplicationContext()); 35 } else { 36 assertNotDestroyed(activity); 37 android.app.FragmentManager fm = activity.getFragmentManager(); 38 return fragmentGet(activity, fm, null /*parentHint*/); 39 } 40}
看上面的: get(FragmentActivity activity) get (Activity activity) 方法都会闲判断一下是否是后台线程 if (Util.isOnBackgroundThread()) 如果是后台线程最后会执行getApplicationManager(Context context)方法,也就是我们的我们上面最开始说的那个方法。否则,则都会创建一个fragment添加到活动中,也就是glide中的SupportRequestManagerFragment类,为什么要弄fragment绑定活动中,简答来看看SupportRequestManagerFragment的代码。
1public class SupportRequestManagerFragment extends Fragment { 2 3 4 /** 5 * Returns true if the fragment is a descendant of our parent. 6 */ 7 private boolean isDescendant(Fragment fragment) { 8 Fragment root = this.getParentFragmentUsingHint(); 9 Fragment parentFragment; 10 while ((parentFragment = fragment.getParentFragment()) != null) { 11 if (parentFragment.equals(root)) { 12 return true; 13 } 14 fragment = fragment.getParentFragment(); 15 } 16 return false; 17 } 18 19 private void registerFragmentWithRoot(FragmentActivity activity) { 20 unregisterFragmentWithRoot(); 21 rootRequestManagerFragment = Glide.get(activity).getRequestManagerRetriever() 22 .getSupportRequestManagerFragment(activity.getSupportFragmentManager(), null); 23 if (!this.equals(rootRequestManagerFragment)) { 24 rootRequestManagerFragment.addChildRequestManagerFragment(this); 25 } 26 } 27 28 private void unregisterFragmentWithRoot() { 29 if (rootRequestManagerFragment != null) { 30 rootRequestManagerFragment.removeChildRequestManagerFragment(this); 31 rootRequestManagerFragment = null; 32 } 33 } 34 35 @Override 36 public void onAttach(Context context) { 37 super.onAttach(context); 38 try { 39 registerFragmentWithRoot(getActivity()); 40 } catch (IllegalStateException e) { 41 // OnAttach can be called after the activity is destroyed, see #497. 42 if (Log.isLoggable(TAG, Log.WARN)) { 43 Log.w(TAG, "Unable to register fragment with root", e); 44 } 45 } 46 } 47 48 @Override 49 public void onDetach() { 50 super.onDetach(); 51 parentFragmentHint = null; 52 unregisterFragmentWithRoot(); 53 } 54 55 @Override 56 public void onStart() { 57 super.onStart(); 58 lifecycle.onStart(); 59 } 60 61 @Override 62 public void onStop() { 63 super.onStop(); 64 lifecycle.onStop(); 65 } 66 67 @Override 68 public void onDestroy() { 69 super.onDestroy(); 70 lifecycle.onDestroy(); 71 unregisterFragmentWithRoot(); 72 } 73}
上面的内容有删除,我们这里重点关注一下生命周期里面调用的相应的接口。对这里在监听faagment的生命周期,我们知道activity销毁的时候fragment也会销毁,那么我们监听fargment也就拿到了activity的生命周期,这样在activity销毁的时候我们就可以对图片资源加载进行相应的操作,比如当我们的activity销毁以后他的图片就i没必要再进行加载了,可以进行相应的停止。
Load方法
Load方法用来设置我们的url地址 调用的方法都在RequestBuilder类中的 我们可以看到load方法后调用了loadGeneric方法 最终把赋值给了model字段,然后更改了一个变量的状态,看这个变量名称意思应该是是否设置model,现在是为true。
1public RequestBuilder<TranscodeType> load(@Nullable Object model) { 2 return loadGeneric(model); 3} 4 5private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) { 6 this.model = model; 7 isModelSet = true; 8 return this; 9}
into方法
into方法开始也是在RequestBuild类中开始调用 可以看到RequestBuild中有泛型,这泛型稍后再去理解。 这边into方法中传了一个imageview对象,根据注释我们可以了解到,当进行into方法的时候就说明开始启动了图片加载,如果这个view之前正在加载中则会取消之前的任务,重新开始任务。 进去into方法以后可以看到首先就行了一些裁剪方面的设置,判断完之后return时候调用的into方法才是重头戏。 Return调用的into方法有三个参数,第二是null,第三个是请求参数构造(请求的选项)第一个参数分析
1public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) { 2 Util.assertMainThread(); 3 Preconditions.checkNotNull(view); 4 5 RequestOptions requestOptions = this.requestOptions; 6 if (!requestOptions.isTransformationSet() 7 && requestOptions.isTransformationAllowed() 8 && view.getScaleType() != null) { 9 // Clone in this method so that if we use this RequestBuilder to load into a View and then 10 // into a different target, we don't retain the transformation applied based on the previous 11 // View's scale type. 12 switch (view.getScaleType()) { 13 case CENTER_CROP: 14 requestOptions = requestOptions.clone().optionalCenterCrop(); 15 break; 16 case CENTER_INSIDE: 17 requestOptions = requestOptions.clone().optionalCenterInside(); 18 break; 19 case FIT_CENTER: 20 case FIT_START: 21 case FIT_END: 22 requestOptions = requestOptions.clone().optionalFitCenter(); 23 break; 24 case FIT_XY: 25 requestOptions = requestOptions.clone().optionalCenterInside(); 26 break; 27 case CENTER: 28 case MATRIX: 29 default: 30 // Do nothing. 31 } 32 } 33 34 return into( 35 glideContext.buildImageViewTarget(view, transcodeClass), 36 /*targetListener=*/ null, 37 requestOptions); 38}
分析一下glideContext.buildImageViewTarget()
1@NonNull 2public <X> ViewTarget<ImageView, X> buildImageViewTarget( 3 @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) { 4 return imageViewTargetFactory.buildTarget(imageView, transcodeClass); 5}
接着我们就来来到了ImageViewTargetFactory类,里面就这么一个方法bildTarget,来看看这个方法事干嘛的,很显然事返回图片的类型,这里有俩种Bitmap,Drawable。最后返回了一个ViewTaget对象。视图目标对象。
1public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view, 2 @NonNull Class<Z> clazz) { 3 if (Bitmap.class.equals(clazz)) { 4 return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); 5 } else if (Drawable.class.isAssignableFrom(clazz)) { 6 return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); 7 } else { 8 throw new IllegalArgumentException( 9 "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); 10 } 11}
分析完第一次参数以后接着走来到了下面的into方法:
1private <Y extends Target<TranscodeType>> Y into( 2 @NonNull Y target, 3 @Nullable RequestListener<TranscodeType> targetListener, 4 @NonNull RequestOptions options) { 5 Util.assertMainThread(); 6 Preconditions.checkNotNull(target); 7 if (!isModelSet) { 8 throw new IllegalArgumentException("You must call #load() before calling #into()"); 9 } 10 11 options = options.autoClone(); 12 Request request = buildRequest(target, targetListener, options); 13 14 Request previous = target.getRequest(); 15 if (request.isEquivalentTo(previous) 16 && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { 17 request.recycle(); 18 if (!Preconditions.checkNotNull(previous).isRunning()) { 19 previous.begin(); 20 } 21 return target; 22 } 23 24 requestManager.clear(target); 25 target.setRequest(request); 26 requestManager.track(target, request); 27 28 return target; 29} 30 31先看这个
判断
1if (request.isEquivalentTo(previous) 2 && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous))
第一个request与previous是否相等,第二个 !options.isMemoryCacheable() && previous.isComplete() 第二个第一个是否内存缓存 第二个第二个previous请求是否完成,只有当不使用内存缓存以及previous请求完成的时候才能过。 进来了就先释放掉request资源,然后再检查previous是否为空,不为空是否在运行,如果不再运行则发起请求。 接着往下面走,先在requestManager管理中清除这个target目标,然后重新发起。 现在我们接着看requestManager.track()方法。
1void track(Target<?> target, Request request) { 2 targetTracker.track(target); 3 requestTracker.runRequest(request); 4} 5接着看requestTracker.runRequest()方法。 6public void runRequest(Request request) { 7 requests.add(request); 8 if (!isPaused) { 9 request.begin(); 10 } else { 11 pendingRequests.add(request); 12 } 13}
这个方法的注释也明确的告诉了我们 开始跟踪给定的请求。这里有一个参数isPauesd默认事为true,那么我们当启动app第一次进来的时候请求就不会在这里被执行,而是都添加集合中等待执行。这里俩个集合说明一下。 private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>()); private final List<Request> pendingRequests = new ArrayList<>(); 第一个集合requests是请求集合 弱引用 第二个集合pendingRequests是待请求集合 强引用 第一个就是为了发送执行,第二个的作用就是为了保持引用,防止弱引用被回收。
那么上面我说了isPaused这个字段第一次运行默认是为false的,那么虽然你添加进去了,但是这里不会去执行操作,这个开始网络请求的操作在哪里开始执行呢,当我们第一次进来的时候,
1public void resumeRequests() { 2 isPaused = false; 3 for (Request request : Util.getSnapshot(requests)) { 4 if (!request.isComplete() && !request.isCancelled() && !request.isRunning()) { 5 request.begin(); 6 } 7 } 8 pendingRequests.clear(); 9} 10 11RequestManager: 12public void onStart() { 13 resumeRequests(); 14 targetTracker.onStart(); 15}
没错当我们第一进来的时候是在这里开始执行我们的网络请求的,当我们的生命周期走到了onStart的时候,就会把原本等待队列中的网络请求开始执行。这也对应了我们生命周期的方法,生命周期存在的时候发送网络请求,不然界面都没有你加载图片也没意义,那么当我们生命周期开始走到销毁的时候就会停止一切图片加载,界面都要销毁了你还加载图片干嘛,这不是浪费资源吗。这里对于怎么监听activity的生命周期上面也有介绍就是添加了一个fragment和activity绑定。 当第一次以后我们的ispaues会变成true状态,所以之后我们进行的图片加载会直接发送网络请求,不会进入到强引用队列中等待。
END
Glide的缓存机制刨析
我们自己都知道,如果你来写一个图片加载框架,肯定会想到做缓存减少不必要的网络请求,所以glide也不例外。
待续