From 9521df7c73493d8a52c85f963cf6b87fe70e2d51 Mon Sep 17 00:00:00 2001 From: lishuai Date: Mon, 1 Nov 2021 16:22:03 +0800 Subject: [PATCH 1/9] =?UTF-8?q?glide.with=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bumptech/glide/RequestManager.java | 37 ++++++------ .../manager/RequestManagerRetriever.java | 60 +++++++++++++++---- 2 files changed, 69 insertions(+), 28 deletions(-) diff --git a/library/src/main/java/com/bumptech/glide/RequestManager.java b/library/src/main/java/com/bumptech/glide/RequestManager.java index a4d2319788..9d47390b92 100644 --- a/library/src/main/java/com/bumptech/glide/RequestManager.java +++ b/library/src/main/java/com/bumptech/glide/RequestManager.java @@ -56,6 +56,7 @@ */ public class RequestManager implements ComponentCallbacks2, LifecycleListener, ModelTypes> { + private static final RequestOptions DECODE_TYPE_BITMAP = decodeTypeOf(Bitmap.class).lock(); private static final RequestOptions DECODE_TYPE_GIF = decodeTypeOf(GifDrawable.class).lock(); private static final RequestOptions DOWNLOAD_ONLY_OPTIONS = @@ -94,7 +95,7 @@ public void run() { private RequestOptions requestOptions; private boolean pauseAllRequestsOnTrimMemoryModerate; - + // TODO: Glide源码-Glide.with(context)-->RequestManager的创建 public RequestManager( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @@ -109,7 +110,7 @@ public RequestManager( context); } - // Our usage is safe here. + // TODO: Glide源码-Glide.with(context)-->RequestManager的创建 @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") RequestManager( Glide glide, @@ -133,17 +134,20 @@ public RequestManager( // In that case we cannot risk synchronously pausing or resuming requests, so we hack around the // issue by delaying adding ourselves as a lifecycle listener by posting to the main thread. // This should be entirely safe. + //子线程通过主线程 post添加到lifecycle中 if (Util.isOnBackgroundThread()) { Util.postOnUiThread(addSelfToLifecycle); } else { + //将rm添加到lifecycle,该lifecycle在frag中 lifecycle.addListener(this); } + //添加了一个网络变化监听 lifecycle.addListener(connectivityMonitor); defaultRequestListeners = new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners()); setRequestOptions(glide.getGlideContext().getDefaultRequestOptions()); - + //最后将rm添加到glide的managers集合中--用于内存管理 ,onDestroy时,清除 glide.registerRequestManager(this); } @@ -169,8 +173,8 @@ private synchronized void updateRequestOptions(@NonNull RequestOptions toUpdate) * *

The modified options will only be applied to loads started after this method is called. * - * @see RequestBuilder#apply(BaseRequestOptions) * @return This request manager. + * @see RequestBuilder#apply(BaseRequestOptions) */ @NonNull public synchronized RequestManager applyDefaultRequestOptions( @@ -191,8 +195,8 @@ public synchronized RequestManager applyDefaultRequestOptions( * {@link RequestOptions} provided here. Instead the manager will create a clone of these options * and mutate the clone. * - * @see #applyDefaultRequestOptions(RequestOptions) * @return This request manager. + * @see #applyDefaultRequestOptions(RequestOptions) */ @NonNull public synchronized RequestManager setDefaultRequestOptions( @@ -263,10 +267,9 @@ public synchronized void pauseRequests() { * automatically resume onStart(). * *

This will release the memory used by completed bitmaps but leaves them in any configured - * caches. When an #{@link android.app.Activity} receives #{@link - * android.app.Activity#onTrimMemory(int)} at a level of #{@link - * android.content.ComponentCallbacks2#TRIM_MEMORY_BACKGROUND} this is desirable in order to keep - * your process alive longer. + * caches. When an #{@link android.app.Activity} receives #{@link android.app.Activity#onTrimMemory(int)} + * at a level of #{@link android.content.ComponentCallbacks2#TRIM_MEMORY_BACKGROUND} this is + * desirable in order to keep your process alive longer. * * @see #isPaused() * @see #resumeRequests() @@ -391,8 +394,7 @@ public RequestBuilder asBitmap() { } /** - * Attempts to always load the resource as a {@link - * com.bumptech.glide.load.resource.gif.GifDrawable}. + * Attempts to always load the resource as a {@link com.bumptech.glide.load.resource.gif.GifDrawable}. * *

If the underlying data is not a GIF, this will fail. As a result, this should only be used * if the model represents an animated GIF and the caller wants to interact with the GifDrawable @@ -400,8 +402,7 @@ public RequestBuilder asBitmap() { * whether or not the given data represents an animated GIF and return the appropriate {@link * Drawable}, animated or not, automatically. * - * @return A new request builder for loading a {@link - * com.bumptech.glide.load.resource.gif.GifDrawable}. + * @return A new request builder for loading a {@link com.bumptech.glide.load.resource.gif.GifDrawable}. */ @NonNull @CheckResult @@ -542,7 +543,8 @@ public RequestBuilder load(@Nullable Object model) { * *

This method is designed to work for remote data that is or will be cached using {@link * com.bumptech.glide.load.engine.DiskCacheStrategy#DATA}. As a result, specifying a {@link - * com.bumptech.glide.load.engine.DiskCacheStrategy} on this request is generally not recommended. + * com.bumptech.glide.load.engine.DiskCacheStrategy} on this request is generally not + * recommended. * * @return A new request builder for downloading content to cache and returning the cache File. */ @@ -580,9 +582,8 @@ public RequestBuilder asFile() { } /** - * Attempts to load the resource using any registered {@link - * com.bumptech.glide.load.ResourceDecoder}s that can decode the given resource class or any - * subclass of the given resource class. + * Attempts to load the resource using any registered {@link com.bumptech.glide.load.ResourceDecoder}s + * that can decode the given resource class or any subclass of the given resource class. * * @param resourceClass The resource to decode. * @return A new request builder for loading the given resource class. @@ -603,7 +604,7 @@ public RequestBuilder as( * * @param view The view to cancel loads and free resources for. * @throws IllegalArgumentException if an object other than Glide's metadata is put as the view's - * tag. + * tag. * @see #clear(Target) */ public void clear(@NonNull View view) { diff --git a/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java b/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java index 53136d8f7a..1a81ca373b 100644 --- a/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java +++ b/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java @@ -47,21 +47,28 @@ public class RequestManagerRetriever implements Handler.Callback { // allow us to iterate over and retrieve all active Fragments in a FragmentManager. private static final String FRAGMENT_INDEX_KEY = "key"; - /** The top application level RequestManager. */ + /** + * The top application level RequestManager. + */ private volatile RequestManager applicationManager; - /** Pending adds for RequestManagerFragments. */ + /** + * Pending adds for RequestManagerFragments. + */ @SuppressWarnings("deprecation") @VisibleForTesting final Map pendingRequestManagerFragments = new HashMap<>(); - /** Pending adds for SupportRequestManagerFragments. */ - @VisibleForTesting - final Map pendingSupportRequestManagerFragments = + /** + * Pending adds for SupportRequestManagerFragments. + */ + @VisibleForTesting final Map pendingSupportRequestManagerFragments = new HashMap<>(); - /** Main thread handler to handle cleaning up pending fragment maps. */ + /** + * Main thread handler to handle cleaning up pending fragment maps. + */ private final Handler handler; private final RequestManagerFactory factory; @@ -119,6 +126,7 @@ private RequestManager getApplicationManager(@NonNull Context context) { return applicationManager; } + // TODO: Glide源码-Glide.with(context)--调用RequestManagerRetriever.get()获取RequestManager @NonNull public RequestManager get(@NonNull Context context) { if (context == null) { @@ -136,11 +144,13 @@ public RequestManager get(@NonNull Context context) { return get(((ContextWrapper) context).getBaseContext()); } } - + //TODO: 子线程或ApplicationContext,直接创建ApplicationRequestManager->new RequestManager(glide, lifecycle, requestManagerTreeNode, context) return getApplicationManager(context); } @NonNull + // TODO: Glide源码-Glide.with(context)--调用RequestManagerRetriever.get()获取RequestManager + //androidx public RequestManager get(@NonNull FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); @@ -173,8 +183,11 @@ public RequestManager get(@NonNull Fragment fragment) { } @SuppressWarnings("deprecation") + // TODO: Glide源码-Glide.with(context)--调用RequestManagerRetriever.get()获取RequestManager + //app包 @NonNull public RequestManager get(@NonNull Activity activity) { + //非主线程,传入applicationContext if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else if (activity instanceof FragmentActivity) { @@ -183,6 +196,9 @@ public RequestManager get(@NonNull Activity activity) { assertNotDestroyed(activity); frameWaiter.registerSelf(activity); android.app.FragmentManager fm = activity.getFragmentManager(); + // 创建空白fragment绑定页面监听生命周期变化, + // 将requestManager传给fragment用来接收生命周期变化, + // 返回requestManager return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); } } @@ -382,16 +398,27 @@ RequestManagerFragment getRequestManagerFragment(Activity activity) { @SuppressWarnings("deprecation") @NonNull + // TODO: Glide源码-Glide.with(context)--创建空白fragment,绑定页面 + //这里是app包下的Fragment private RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) { + //先根据tag获取,如果已经绑定过 RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { + //先从hashmap中获取,缓存作用,避免重复创建fragment current = pendingRequestManagerFragments.get(fm); if (current == null) { + //创建fragment current = new RequestManagerFragment(); + //fragment中绑定fragmetn用--分支 current.setParentFragmentHint(parentHint); + //放入hashMap缓存中 pendingRequestManagerFragments.put(fm, current); + //绑定页面 fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); + //发送handler消息,因为绑定fragment是基于handler消息的, + //这里发送消息,一定会在绑定fragment消息之后,消费这个消息时说明绑定过程已经结束。 + //所以hashMap防止重复创建就可以消除了,上面第一步直接可以从通过tag获取到了。 handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } @@ -400,26 +427,33 @@ private RequestManagerFragment getRequestManagerFragment( @SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"}) @Deprecated + // TODO: Glide源码-Glide.with(context)--创建空白fragment,创建requestManager,传给fragment,返回requestManager @NonNull private RequestManager fragmentGet( @NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { + //创建fragment RequestManagerFragment current = getRequestManagerFragment(fm, parentHint); + //先获取frag中的requestManager,因为这里的frag有可能是通过byTag获取已经绑定过的frag. RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { - // TODO(b/27524013): Factor out this Glide.get() call. Glide glide = Glide.get(context); + //通过建造者创建requestManager,传入glide和frag在创建时创建的lifecycle,用于生命周期变化通知。 + //调用requestManager构造方法,将rm作为LifecycleListener,传给frag的lifecycle中-> requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); // This is a bit of hack, we're going to start the RequestManager, but not the // corresponding Lifecycle. It's safe to start the RequestManager, but starting the // Lifecycle might trigger memory leaks. See b/154405040 + //activity可见的,则调用rm的onStart方法 + //如果已经有执行的请求就开始 if (isParentVisible) { requestManager.onStart(); } + //将rm设置给fragment current.setRequestManager(requestManager); } return requestManager; @@ -437,6 +471,8 @@ private static boolean isActivityVisible(Context context) { return activity == null || !activity.isFinishing(); } + // TODO: Glide源码-Glide.with(context)--创建空白fragment,绑定页面 + //这里是androidX包下的Fragment @NonNull private SupportRequestManagerFragment getSupportRequestManagerFragment( @NonNull final FragmentManager fm, @Nullable Fragment parentHint) { @@ -456,15 +492,16 @@ private SupportRequestManagerFragment getSupportRequestManagerFragment( } @NonNull + // TODO: Glide源码-Glide.with(context)--创建空白fragment,创建requestManager,传给fragment,返回requestManager private RequestManager supportFragmentGet( @NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) { + //创建空白fragment SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { - // TODO(b/27524013): Factor out this Glide.get() call. Glide glide = Glide.get(context); requestManager = factory.build( @@ -506,7 +543,9 @@ public boolean handleMessage(Message message) { return handled; } - /** Used internally to create {@link RequestManager}s. */ + /** + * Used internally to create {@link RequestManager}s. + */ public interface RequestManagerFactory { @NonNull RequestManager build( @@ -525,6 +564,7 @@ public RequestManager build( @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) { + //调用构造方法 return new RequestManager(glide, lifecycle, requestManagerTreeNode, context); } }; From 1d1d4e60c0136b7576f2de8ead0b37758951a6bb Mon Sep 17 00:00:00 2001 From: lishuai Date: Mon, 1 Nov 2021 16:22:49 +0800 Subject: [PATCH 2/9] =?UTF-8?q?glide.with=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/bumptech/glide/Glide.java | 75 ++++++++++++++----- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/library/src/main/java/com/bumptech/glide/Glide.java b/library/src/main/java/com/bumptech/glide/Glide.java index 4951007c00..5d2119be97 100644 --- a/library/src/main/java/com/bumptech/glide/Glide.java +++ b/library/src/main/java/com/bumptech/glide/Glide.java @@ -153,7 +153,7 @@ public static File getPhotoCacheDir(@NonNull Context context) { * Returns a directory with the given name in the private cache directory of the application to * use to store retrieved media and thumbnails. * - * @param context A context. + * @param context A context. * @param cacheName The name of the subdirectory in which to store the cache. * @see #getPhotoCacheDir(android.content.Context) */ @@ -181,13 +181,16 @@ public static File getPhotoCacheDir(@NonNull Context context, @NonNull String ca */ @NonNull // Double checked locking is safe here. + // TODO: Glide源码-Glide.with(context)--获取单例Glide @SuppressWarnings("GuardedBy") public static Glide get(@NonNull Context context) { + //双重检查锁DCL if (glide == null) { GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(context.getApplicationContext()); synchronized (Glide.class) { if (glide == null) { + //检查并初始化Glide checkAndInitializeGlide(context, annotationGeneratedModule); } } @@ -196,6 +199,7 @@ public static Glide get(@NonNull Context context) { return glide; } + // TODO: Glide源码-Glide.with(context)--获取单例Glide @GuardedBy("Glide.class") private static void checkAndInitializeGlide( @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) { @@ -207,14 +211,15 @@ private static void checkAndInitializeGlide( + " use the provided Glide instance instead"); } isInitializing = true; + // TODO: Glide源码-Glide.with(context)--获取单例Glide-初始化 initializeGlide(context, generatedAppGlideModule); isInitializing = false; } /** * @deprecated Use {@link #init(Context, GlideBuilder)} to get a singleton compatible with Glide's - * generated API. - *

This method will be removed in a future version of Glide. + * generated API. + *

This method will be removed in a future version of Glide. */ @VisibleForTesting @Deprecated @@ -260,12 +265,15 @@ public static void tearDown() { } } + // TODO: Glide源码-Glide.with(context)--获取单例Glide-初始化 @GuardedBy("Glide.class") private static void initializeGlide( @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) { + //使用 GlideBuilder 建造者模式创建glide initializeGlide(context, new GlideBuilder(), generatedAppGlideModule); } + // TODO: Glide源码-Glide.with(context)--获取单例Glide-初始化 @GuardedBy("Glide.class") @SuppressWarnings("deprecation") private static void initializeGlide( @@ -304,6 +312,7 @@ private static void initializeGlide( annotationGeneratedModule != null ? annotationGeneratedModule.getRequestManagerFactory() : null; + //设置RequestManagerFactory工厂 builder.setRequestManagerFactory(factory); for (com.bumptech.glide.module.GlideModule module : manifestModules) { module.applyOptions(applicationContext, builder); @@ -311,6 +320,7 @@ private static void initializeGlide( if (annotationGeneratedModule != null) { annotationGeneratedModule.applyOptions(applicationContext, builder); } + // TODO: Glide源码-Glide.with(context)--获取单例Glide-建造者模式->build Glide glide = builder.build(applicationContext); for (com.bumptech.glide.module.GlideModule module : manifestModules) { try { @@ -372,6 +382,7 @@ private static void throwIncorrectGlideModule(Exception e) { e); } + // TODO: Glide源码-Glide.with(context)--获取单例Glide-构造函数 @SuppressWarnings("PMD.UnusedFormalParameter") Glide( @NonNull Context context, @@ -395,7 +406,7 @@ private static void throwIncorrectGlideModule(Exception e) { this.defaultRequestOptionsFactory = defaultRequestOptionsFactory; final Resources resources = context.getResources(); - + //组件注册 registry = new Registry(); registry.register(new DefaultImageHeaderParser()); // Right now we're only using this parser for HEIF images, which are only supported on OMR1+. @@ -443,10 +454,19 @@ private static void throwIncorrectGlideModule(Exception e) { ContentResolver contentResolver = context.getContentResolver(); registry + //encoderRegistry + //byte写入文件File .append(ByteBuffer.class, new ByteBufferEncoder()) + //encoderRegistry + //将流写入磁盘的Encoder .append(InputStream.class, new StreamEncoder(arrayPool)) + /* Bitmaps */ + //decoderRegistry + //byte->Bitmap .append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder) + //decoderRegistry + //Stream->Bitmap .append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder); if (ParcelFileDescriptorRewinder.isSupported()) { @@ -525,6 +545,7 @@ Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitm } registry + //用于从 Android 资源 ID 加载InputStream的工厂 .append(int.class, InputStream.class, resourceLoaderStreamFactory) .append(int.class, ParcelFileDescriptor.class, resourceLoaderFileDescriptorFactory) .append(Integer.class, InputStream.class, resourceLoaderStreamFactory) @@ -533,8 +554,10 @@ Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitm .append(int.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory) .append(Integer.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory) .append(int.class, Uri.class, resourceLoaderUriFactory) + //从Uri加载 .append(String.class, InputStream.class, new DataUrlLoader.StreamFactory()) .append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory()) + //从String加载InputStream .append(String.class, InputStream.class, new StringLoader.StreamFactory()) .append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory()) .append( @@ -567,6 +590,7 @@ Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitm .append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory()) .append(URL.class, InputStream.class, new UrlLoader.StreamFactory()) .append(Uri.class, File.class, new MediaStoreFileLoader.Factory(context)) + //用于平移GlideUrl (HTTP / HTTPS URLS)到InputStream数据。 .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory()) .append(byte[].class, ByteBuffer.class, new ByteArrayLoader.ByteBufferFactory()) .append(byte[].class, InputStream.class, new ByteArrayLoader.StreamFactory()) @@ -592,8 +616,9 @@ Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitm BitmapDrawable.class, new BitmapDrawableDecoder<>(resources, byteBufferVideoDecoder)); } - + //创建了一个ImageViewTargetFactory ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory(); + //创建了一个GlideContext对象 glideContext = new GlideContext( context, @@ -636,7 +661,9 @@ public ArrayPool getArrayPool() { return arrayPool; } - /** @return The context associated with this instance. */ + /** + * @return The context associated with this instance. + */ @NonNull public Context getContext() { return glideContext.getBaseContext(); @@ -669,7 +696,7 @@ GlideContext getGlideContext() { * every rotation. * * @param bitmapAttributeBuilders The list of {@link Builder Builders} representing individual - * sizes and configurations of {@link Bitmap}s to be pre-filled. + * sizes and configurations of {@link Bitmap}s to be pre-filled. */ @SuppressWarnings("unused") // Public API public synchronized void preFillBitmapPool( @@ -731,7 +758,9 @@ public void clearDiskCache() { engine.clearDiskCache(); } - /** Internal method. */ + /** + * Internal method. + */ @NonNull public RequestManagerRetriever getRequestManagerRetriever() { return requestManagerRetriever; @@ -762,6 +791,7 @@ public MemoryCategory setMemoryCategory(@NonNull MemoryCategory memoryCategory) return oldCategory; } + // TODO: Glide源码-Glide.with(context)--获取RequestManagerRetriever @NonNull private static RequestManagerRetriever getRetriever(@Nullable Context context) { // Context could be null for other reasons (ie the user passes in null), but in practice it will @@ -771,6 +801,7 @@ private static RequestManagerRetriever getRetriever(@Nullable Context context) { "You cannot start a load on a not yet attached View or a Fragment where getActivity() " + "returns null (which usually occurs when getActivity() is called before the Fragment " + "is attached or after the Fragment is destroyed)."); + // TODO: Glide源码-Glide.with(context)--获取单例Glide并且获取其对应的retriever return Glide.get(context).getRequestManagerRetriever(); } @@ -786,7 +817,8 @@ private static RequestManagerRetriever getRetriever(@Nullable Context context) { * the same vein, if the resource will be used in a view in an activity, the load should be * started with {@link #with(android.app.Activity)}}. * - *

This method is appropriate for resources that will be used outside of the normal fragment or + *

This method is appropriate for resources that will be used outside of the normal fragment + * or * activity lifecycle (For example in services, or for notification thumbnails). * * @param context Any context, will not be retained. @@ -796,6 +828,7 @@ private static RequestManagerRetriever getRetriever(@Nullable Context context) { * @see #with(androidx.fragment.app.Fragment) * @see #with(androidx.fragment.app.FragmentActivity) */ + // TODO: Glide源码-Glide.with(context)返回RequestManager流程 @NonNull public static RequestManager with(@NonNull Context context) { return getRetriever(context).get(context); @@ -808,15 +841,20 @@ public static RequestManager with(@NonNull Context context) { * @param activity The activity to use. * @return A RequestManager for the given activity that can be used to start a load. */ + + // TODO: Glide源码-Glide.with(context)--返回RequestManager流程 @NonNull public static RequestManager with(@NonNull Activity activity) { - return getRetriever(activity).get(activity); + // TODO: Glide源码-Glide.with(context)--获取RequestManagerRetriever,然后获取RequestManager + return getRetriever(activity) + // TODO: Glide源码-Glide.with(context)--调用RequestManagerRetriever.get()获取RequestManager + .get(activity); } /** - * Begin a load with Glide that will tied to the give {@link - * androidx.fragment.app.FragmentActivity}'s lifecycle and that uses the given {@link - * androidx.fragment.app.FragmentActivity}'s default options. + * Begin a load with Glide that will tied to the give {@link androidx.fragment.app.FragmentActivity}'s + * lifecycle and that uses the given {@link androidx.fragment.app.FragmentActivity}'s default + * options. * * @param activity The activity to use. * @return A RequestManager for the given FragmentActivity that can be used to start a load. @@ -845,8 +883,7 @@ public static RequestManager with(@NonNull Fragment fragment) { * @param fragment The fragment to use. * @return A RequestManager for the given Fragment that can be used to start a load. * @deprecated Prefer support Fragments and {@link #with(Fragment)} instead, {@link - * android.app.Fragment} will be deprecated. See - * https://github.com/android/android-ktx/pull/161#issuecomment-363270555. + * android.app.Fragment} will be deprecated. See https://github.com/android/android-ktx/pull/161#issuecomment-363270555. */ @SuppressWarnings("deprecation") @Deprecated @@ -935,10 +972,14 @@ public void onLowMemory() { clearMemory(); } - /** Creates a new instance of {@link RequestOptions}. */ + /** + * Creates a new instance of {@link RequestOptions}. + */ public interface RequestOptionsFactory { - /** Returns a non-null {@link RequestOptions} object. */ + /** + * Returns a non-null {@link RequestOptions} object. + */ @NonNull RequestOptions build(); } From c1c165f1e4b801322f63527184f92816a38c860a Mon Sep 17 00:00:00 2001 From: lishuai Date: Mon, 1 Nov 2021 18:24:27 +0800 Subject: [PATCH 3/9] =?UTF-8?q?glide.load=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/bumptech/glide/RequestManager.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/bumptech/glide/RequestManager.java b/library/src/main/java/com/bumptech/glide/RequestManager.java index 9d47390b92..890b8e7e3a 100644 --- a/library/src/main/java/com/bumptech/glide/RequestManager.java +++ b/library/src/main/java/com/bumptech/glide/RequestManager.java @@ -388,6 +388,7 @@ public synchronized void onDestroy() { * @return A new request builder for loading a {@link android.graphics.Bitmap} */ @NonNull + // TODO: Glide源码-load:先.asBitmap()再.load("url")-使用Bitmap的RequestOptions @CheckResult public RequestBuilder asBitmap() { return as(Bitmap.class).apply(DECODE_TYPE_BITMAP); @@ -406,6 +407,7 @@ public RequestBuilder asBitmap() { */ @NonNull @CheckResult + // TODO: Glide源码-load:先.asGif()再.load("url")-使用GifDrawable的RequestOptions public RequestBuilder asGif() { return as(GifDrawable.class).apply(DECODE_TYPE_GIF); } @@ -423,6 +425,7 @@ public RequestBuilder asGif() { @NonNull @CheckResult public RequestBuilder asDrawable() { + // TODO: Glide源码-load--创建RequestBuilder return as(Drawable.class); } @@ -457,9 +460,13 @@ public RequestBuilder load(@Nullable Drawable drawable) { */ @NonNull @CheckResult + // TODO: Glide源码-load:默认Drawable-使用默认的 new RequestOptions @Override public RequestBuilder load(@Nullable String string) { - return asDrawable().load(string); +// TODO: Glide源码-load--创建RequestBuilder-默认情况使用asDrawable() + return asDrawable() + //设置 model + .load(string); } /** @@ -592,6 +599,7 @@ public RequestBuilder asFile() { @CheckResult public RequestBuilder as( @NonNull Class resourceClass) { + // TODO: Glide源码-load--创建RequestBuilder-传入glide,rm,context,resourceClass(drawable,bitmap,GifDrawable,File) return new RequestBuilder<>(glide, this, resourceClass, context); } From bd07947a843da8147ca9a22fd25b02a5ef906859 Mon Sep 17 00:00:00 2001 From: lis Date: Mon, 1 Nov 2021 22:17:35 +0800 Subject: [PATCH 4/9] =?UTF-8?q?glide.info=E6=B5=81=E7=A8=8B-=E6=9E=84?= =?UTF-8?q?=E5=BB=BARequest=EF=BC=8C=E6=AD=A3=E5=B8=B8=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E7=9A=84=E6=98=AFSingleRequest=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/bumptech/glide/GlideContext.java | 1 + .../com/bumptech/glide/RequestBuilder.java | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/library/src/main/java/com/bumptech/glide/GlideContext.java b/library/src/main/java/com/bumptech/glide/GlideContext.java index f312830b18..439a0258a8 100644 --- a/library/src/main/java/com/bumptech/glide/GlideContext.java +++ b/library/src/main/java/com/bumptech/glide/GlideContext.java @@ -97,6 +97,7 @@ public TransitionOptions getDefaultTransitionOptions(@NonNull Class @NonNull public ViewTarget buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class transcodeClass) { + //构建ImageViewTarget return imageViewTargetFactory.buildTarget(imageView, transcodeClass); } diff --git a/library/src/main/java/com/bumptech/glide/RequestBuilder.java b/library/src/main/java/com/bumptech/glide/RequestBuilder.java index a592e119ac..44b979f924 100644 --- a/library/src/main/java/com/bumptech/glide/RequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/RequestBuilder.java @@ -779,17 +779,20 @@ > Y into( Executor callbackExecutor) { return into(target, targetListener, /*options=*/ this, callbackExecutor); } - + // TODO: Glide源码-into流程 private > Y into( @NonNull Y target, @Nullable RequestListener targetListener, BaseRequestOptions options, Executor callbackExecutor) { Preconditions.checkNotNull(target); + //这里的 isModelSet 是在 load 的时候赋值为 true 的,所以不会抛异常 + //调用load设置modle后isModeSet为true if (!isModelSet) { throw new IllegalArgumentException("You must call #load() before calling #into()"); } - + //构建Request target=DrawableImageViewTarget + //最终返回了SingleRequest子类 Request request = buildRequest(target, targetListener, options, callbackExecutor); Request previous = target.getRequest(); @@ -836,10 +839,11 @@ private boolean isSkipMemoryCacheWithCompletePreviousRequest( * ImageView}. */ @NonNull + // TODO: Glide源码-into流程 public ViewTarget into(@NonNull ImageView view) { Util.assertMainThread(); Preconditions.checkNotNull(view); - + // 根据 ImageView 布局中的 scaleType 来重构 requestOptions BaseRequestOptions requestOptions = this; if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() @@ -847,6 +851,7 @@ public ViewTarget into(@NonNull ImageView view) { // Clone in this method so that if we use this RequestBuilder to load into a View and then // into a different target, we don't retain the transformation applied based on the previous // View's scale type. + //如果在 xml ImageView 节点中 没有设置 scaleType 那么默认在构造函数中进行了初始化为 mScaleType = ScaleType.FIT_CENTER; switch (view.getScaleType()) { case CENTER_CROP: requestOptions = requestOptions.clone().optionalCenterCrop(); @@ -868,11 +873,14 @@ public ViewTarget into(@NonNull ImageView view) { // Do nothing. } } - + //调用 into 重载函数,创建一个 ViewTarget return into( + //调用 buildImageViewTarget 构建一个 ImageView 类型的 Target(Bitmap/Drawable(GifDrawable)) + //这里我们使用Drawable.class 返回 DrawableImageViewTarget glideContext.buildImageViewTarget(view, transcodeClass), /*targetListener=*/ null, requestOptions, + //在主线程运动runnable的线程池 Executors.mainThreadExecutor()); } @@ -1020,12 +1028,13 @@ private Priority getThumbnailPriority(@NonNull Priority current) { throw new IllegalArgumentException("unknown priority: " + getPriority()); } } - + //构建Request private Request buildRequest( Target target, @Nullable RequestListener targetListener, BaseRequestOptions requestOptions, Executor callbackExecutor) { + //构建Request return buildRequestRecursive( /*requestLock=*/ new Object(), target, @@ -1057,7 +1066,7 @@ private Request buildRequestRecursive( errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator); parentCoordinator = errorRequestCoordinator; } - + //构建Request Request mainRequest = buildThumbnailRequestRecursive( requestLock, @@ -1097,7 +1106,7 @@ private Request buildRequestRecursive( errorRequestCoordinator.setRequests(mainRequest, errorRequest); return errorRequestCoordinator; } - + //构建Request private Request buildThumbnailRequestRecursive( Object requestLock, Target target, @@ -1109,6 +1118,7 @@ private Request buildThumbnailRequestRecursive( int overrideHeight, BaseRequestOptions requestOptions, Executor callbackExecutor) { + //缩略图,分支先不看 if (thumbnailBuilder != null) { // Recursive case: contains a potentially recursive thumbnail request builder. if (isThumbnailBuilt) { @@ -1206,6 +1216,7 @@ private Request buildThumbnailRequestRecursive( return coordinator; } else { // Base case: no thumbnail. + //构建Request return obtainRequest( requestLock, target, @@ -1219,7 +1230,7 @@ private Request buildThumbnailRequestRecursive( callbackExecutor); } } - + //构建Request private Request obtainRequest( Object requestLock, Target target, @@ -1231,6 +1242,7 @@ private Request obtainRequest( int overrideWidth, int overrideHeight, Executor callbackExecutor) { + //构建Request return SingleRequest.obtain( context, glideContext, From 178620b77c4100fd5a72bda82216a6463d4cca9d Mon Sep 17 00:00:00 2001 From: lishuai Date: Tue, 2 Nov 2021 13:34:23 +0800 Subject: [PATCH 5/9] =?UTF-8?q?glide.into-=E4=BB=8E=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E3=80=81=E7=A3=81=E7=9B=98=E3=80=81=E7=BD=91=E7=BB=9C=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E8=B5=84=E6=BA=90=E5=B9=B6=E8=AE=BE=E7=BD=AE=E7=BB=99?= =?UTF-8?q?ImageView=E7=9A=84=E8=BF=87=E7=A8=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bumptech/glide/RequestBuilder.java | 5 +- .../com/bumptech/glide/RequestManager.java | 4 +- .../glide/load/data/HttpUrlFetcher.java | 4 +- .../glide/load/engine/DataCacheGenerator.java | 2 + .../bumptech/glide/load/engine/DecodeJob.java | 57 ++++++++++++++----- .../glide/load/engine/DecodePath.java | 8 ++- .../bumptech/glide/load/engine/Engine.java | 35 ++++++++---- .../bumptech/glide/load/engine/EngineJob.java | 22 ++++++- .../bumptech/glide/load/engine/LoadPath.java | 7 ++- .../load/engine/ResourceCacheGenerator.java | 3 + .../glide/load/engine/SourceGenerator.java | 12 +++- .../resource/bitmap/StreamBitmapDecoder.java | 1 + .../glide/manager/RequestTracker.java | 3 + .../bumptech/glide/request/SingleRequest.java | 18 +++++- .../glide/request/target/ImageViewTarget.java | 5 +- 15 files changed, 148 insertions(+), 38 deletions(-) diff --git a/library/src/main/java/com/bumptech/glide/RequestBuilder.java b/library/src/main/java/com/bumptech/glide/RequestBuilder.java index 44b979f924..36a511d6f2 100644 --- a/library/src/main/java/com/bumptech/glide/RequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/RequestBuilder.java @@ -795,6 +795,7 @@ private > Y into( //最终返回了SingleRequest子类 Request request = buildRequest(target, targetListener, options, callbackExecutor); + //下面的几行说明是否与上一个请求冲突,一般不用管 直接看下面 else 判断 Request previous = target.getRequest(); if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { @@ -810,9 +811,11 @@ private > Y into( } return target; } - + //清理掉目标请求管理 requestManager.clear(target); + //将request作为tag设置给imageview-在父类ViewTarget中设置的 target.setRequest(request); + //最后是调用 RequestManager 的 track 来执行目标的 Glide request 请求 requestManager.track(target, request); return target; diff --git a/library/src/main/java/com/bumptech/glide/RequestManager.java b/library/src/main/java/com/bumptech/glide/RequestManager.java index 890b8e7e3a..d67dd20ab5 100644 --- a/library/src/main/java/com/bumptech/glide/RequestManager.java +++ b/library/src/main/java/com/bumptech/glide/RequestManager.java @@ -674,9 +674,11 @@ synchronized boolean untrack(@NonNull Target target) { return false; } } - + // TODO: Glide源码-into流程 synchronized void track(@NonNull Target target, @NonNull Request request) { + //添加一个目标任务 targetTracker.track(target); + //执行 Glide request requestTracker.runRequest(request); } diff --git a/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java b/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java index 5602c1498c..364ef06f13 100644 --- a/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java +++ b/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java @@ -49,13 +49,15 @@ public HttpUrlFetcher(GlideUrl glideUrl, int timeout) { this.timeout = timeout; this.connectionFactory = connectionFactory; } - + // TODO: Glide源码-into流程 @Override public void loadData( @NonNull Priority priority, @NonNull DataCallback callback) { long startTime = LogTime.getLogTime(); try { + //http 请求,返回一个 InputStream 输入流 InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders()); + //将 InputStream 以回调形式回调出去-->SourceGenerator#startNextLoad方法中的DataCallback callback.onDataReady(result); } catch (IOException e) { if (Log.isLoggable(TAG, Log.DEBUG)) { diff --git a/library/src/main/java/com/bumptech/glide/load/engine/DataCacheGenerator.java b/library/src/main/java/com/bumptech/glide/load/engine/DataCacheGenerator.java index 939ef09c14..e39ef688c1 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/DataCacheGenerator.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/DataCacheGenerator.java @@ -43,6 +43,7 @@ class DataCacheGenerator implements DataFetcherGenerator, DataFetcher.DataCallba } @Override + // TODO: Glide源码-into流程 public boolean startNext() { GlideTrace.beginSection("DataCacheGenerator.startNext"); try { @@ -57,6 +58,7 @@ public boolean startNext() { // and the actions it performs are much more expensive than a single allocation. @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") Key originalKey = new DataCacheKey(sourceId, helper.getSignature()); + //从磁盘缓存中获取 cacheFile = helper.getDiskCache().get(originalKey); if (cacheFile != null) { this.sourceKey = sourceId; diff --git a/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java b/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java index 74cfc90e9b..902958bf4f 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java @@ -219,6 +219,7 @@ public void cancel() { // We need to rethrow only CallbackException, but not other types of Throwables. @SuppressWarnings("PMD.AvoidRethrowingException") @Override + // TODO: Glide源码-into流程 public void run() { // This should be much more fine grained, but since Java's thread pool implementation silently // swallows all otherwise fatal exceptions, this will at least make it obvious to developers @@ -228,10 +229,12 @@ public void run() { // ensure that the fetcher is cleaned up either way. DataFetcher localFetcher = currentFetcher; try { + //是否取消了当前请求 if (isCancelled) { notifyFailed(); return; } + //执行 runWrapped(); } catch (CallbackException e) { // If a callback not controlled by Glide throws an exception, we should avoid the Glide @@ -268,14 +271,18 @@ public void run() { GlideTrace.endSection(); } } - + // TODO: Glide源码-into流程 private void runWrapped() { switch (runReason) { case INITIALIZE: + //循环取RESOURCE_CACHE,DATA_CACHE和SOURCE stage = getNextStage(Stage.INITIALIZE); + //对应的ResourceCacheGenerator(资源转换后的磁盘缓存),DataCacheGenerator(原始数据的磁盘缓存),SourceGenerator currentGenerator = getNextGenerator(); + //执行 Generator runGenerators(); break; + //切换线程池后重新执行这里 case SWITCH_TO_SOURCE_SERVICE: runGenerators(); break; @@ -301,17 +308,23 @@ private DataFetcherGenerator getNextGenerator() { throw new IllegalStateException("Unrecognized stage: " + stage); } } - + // TODO: Glide源码-into流程 private void runGenerators() { currentThread = Thread.currentThread(); startFetchTime = LogTime.getLogTime(); boolean isStarted = false; + //判断是否取消,是否开始 + //调用 Generator.startNext() 判断是否是属于开始执行的任务 while (!isCancelled && currentGenerator != null + //currentGenerator.startNext()返回true代表命中Generator && !(isStarted = currentGenerator.startNext())) { + //如果没有命中,则下一状态 stage = getNextStage(stage); + //获取下个Generator继续判断是否命中 currentGenerator = getNextGenerator(); + //磁盘缓存没有命中的话直接从网络上获取 if (stage == Stage.SOURCE) { reschedule(); return; @@ -332,10 +345,11 @@ private void notifyFailed() { callback.onLoadFailed(e); onLoadFailed(); } - + // TODO: Glide源码-into流程 private void notifyComplete( Resource resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) { setNotifiedOrThrow(); + // 在 DecodeJob 的构建中, 我们知道这个 Callback 是 EngineJob callback.onResourceReady(resource, dataSource, isLoadedFromAlternateCacheKey); } @@ -368,29 +382,32 @@ private Stage getNextStage(Stage current) { throw new IllegalArgumentException("Unrecognized stage: " + current); } } - + // TODO: Glide源码-into流程 @Override public void reschedule() { runReason = RunReason.SWITCH_TO_SOURCE_SERVICE; + //这里切换线程池重新执行任务 callback.reschedule(this); } + // TODO: Glide源码-into流程-从SourceGenerator回调回来 @Override public void onDataFetcherReady( Key sourceKey, Object data, DataFetcher fetcher, DataSource dataSource, Key attemptedKey) { - this.currentSourceKey = sourceKey; - this.currentData = data; - this.currentFetcher = fetcher; - this.currentDataSource = dataSource; + this.currentSourceKey = sourceKey;//当前返回数据的 key + this.currentData = data;//返回的数据 + this.currentFetcher = fetcher;//返回的数据执行器,这里可以理解为 HttpUrlFetcher + this.currentDataSource = dataSource;//数据来源 url this.currentAttemptingKey = attemptedKey; this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0); - + //线程不一致时会通过回调返回 if (Thread.currentThread() != currentThread) { runReason = RunReason.DECODE_DATA; callback.reschedule(this); } else { GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData"); try { + //解析返回回来的数据 decodeFromRetrievedData(); } finally { GlideTrace.endSection(); @@ -412,7 +429,7 @@ public void onDataFetcherFailed( runGenerators(); } } - + // TODO: Glide源码-into流程 private void decodeFromRetrievedData() { if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey( @@ -427,18 +444,20 @@ private void decodeFromRetrievedData() { } Resource resource = null; try { + // 调用 decodeFrom 解析 数据;HttpUrlFetcher , InputStream , currentDataSource resource = decodeFromData(currentFetcher, currentData, currentDataSource); } catch (GlideException e) { e.setLoggingDetails(currentAttemptingKey, currentDataSource); throwables.add(e); } + //解析完成后,通知下去 if (resource != null) { notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey); } else { runGenerators(); } } - + // TODO: Glide源码-into流程 private void notifyEncodeAndRelease( Resource resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) { GlideTrace.beginSection("DecodeJob.notifyEncodeAndRelease"); @@ -453,11 +472,12 @@ private void notifyEncodeAndRelease( lockedResource = LockedResource.obtain(resource); result = lockedResource; } - + //通知调用层数据已经装备好了 notifyComplete(result, dataSource, isLoadedFromAlternateCacheKey); stage = Stage.ENCODE; try { + //这里就是将资源磁盘缓存 if (deferredEncodeManager.hasResourceToEncode()) { deferredEncodeManager.encode(diskCacheProvider, options); } @@ -469,12 +489,13 @@ private void notifyEncodeAndRelease( // Call onEncodeComplete outside the finally block so that it's not called if the encode // process // throws. + //完成 onEncodeComplete(); } finally { GlideTrace.endSection(); } } - + // TODO: Glide源码-into流程-解析资源 private Resource decodeFromData( DataFetcher fetcher, Data data, DataSource dataSource) throws GlideException { try { @@ -482,6 +503,7 @@ private Resource decodeFromData( return null; } long startTime = LogTime.getLogTime(); + //解析 Resource result = decodeFromFetcher(data, dataSource); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Decoded result " + result, startTime); @@ -493,9 +515,12 @@ private Resource decodeFromData( } @SuppressWarnings("unchecked") + // TODO: Glide源码-into流程-解析资源 private Resource decodeFromFetcher(Data data, DataSource dataSource) throws GlideException { + //获取当前数据类的解析器 LoadPath LoadPath path = decodeHelper.getLoadPath((Class) data.getClass()); + //通过 LoadPath 解析器来解析数据 return runLoadPath(data, dataSource, path); } @@ -524,14 +549,16 @@ private Options getOptionsWithHardwareConfig(DataSource dataSource) { return options; } - + // TODO: Glide源码-into流程-解析资源 private Resource runLoadPath( Data data, DataSource dataSource, LoadPath path) throws GlideException { Options options = getOptionsWithHardwareConfig(dataSource); + //因为这里返回的是一个 InputStream 所以 这里拿到的是 InputStreamRewinder DataRewinder rewinder = glideContext.getRegistry().getRewinder(data); try { // ResourceType in DecodeCallback below is required for compilation to work with gradle. + //将解析资源的任务转移到 Load.path 方法中 return path.load( rewinder, options, width, height, new DecodeCallback(dataSource)); } finally { @@ -564,6 +591,7 @@ public StateVerifier getVerifier() { @Synthetic @NonNull + // TODO: Glide源码-into流程-回调 Resource onResourceDecoded(DataSource dataSource, @NonNull Resource decoded) { @SuppressWarnings("unchecked") Class resourceSubClass = (Class) decoded.get().getClass(); @@ -634,6 +662,7 @@ private final class DecodeCallback implements DecodePath.DecodeCallback { @NonNull @Override + // TODO: Glide源码-into流程-回调 public Resource onResourceDecoded(@NonNull Resource decoded) { return DecodeJob.this.onResourceDecoded(dataSource, decoded); } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/DecodePath.java b/library/src/main/java/com/bumptech/glide/load/engine/DecodePath.java index 8fe172fde8..4ae7a761aa 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/DecodePath.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/DecodePath.java @@ -48,7 +48,7 @@ public DecodePath( + transcodeClass.getSimpleName() + "}"; } - + // TODO: Glide源码-into流程-解析资源 public Resource decode( DataRewinder rewinder, int width, @@ -56,12 +56,16 @@ public Resource decode( @NonNull Options options, DecodeCallback callback) throws GlideException { + //调用 decodeResource 将数据解析成中间资源 Resource decoded = decodeResource(rewinder, width, height, options); + //解析完数据回调出去DecodeJob Resource transformed = callback.onResourceDecoded(decoded); + //转换资源为目标资源BitmapDrawableTranscoder--最后往上返回到DecodeJob#decodeFromRetrievedData 方法中 return transcoder.transcode(transformed, options); } @NonNull + // TODO: Glide源码-into流程-解析资源 private Resource decodeResource( DataRewinder rewinder, int width, int height, @NonNull Options options) throws GlideException { @@ -74,6 +78,7 @@ private Resource decodeResource( } @NonNull + // TODO: Glide源码-into流程-解析资源 private Resource decodeResourceWithList( DataRewinder rewinder, int width, @@ -89,6 +94,7 @@ private Resource decodeResourceWithList( DataType data = rewinder.rewindAndGet(); if (decoder.handles(data, options)) { data = rewinder.rewindAndGet(); + // 调用 ResourceDrawableDecoder.decode 解析数据StreamBitmapDecoder result = decoder.decode(data, width, height, options); } // Some decoders throw unexpectedly. If they do, we shouldn't fail the entire load path, but diff --git a/library/src/main/java/com/bumptech/glide/load/engine/Engine.java b/library/src/main/java/com/bumptech/glide/load/engine/Engine.java index c469e967f5..c945b9e8a3 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/Engine.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/Engine.java @@ -152,6 +152,7 @@ public Engine( * @param height The target height in pixels of the desired resource. * @param cb The callback that will be called when the load completes. */ + // TODO: Glide源码-into流程 public LoadStatus load( GlideContext glideContext, Object model, @@ -173,7 +174,7 @@ public LoadStatus load( ResourceCallback cb, Executor callbackExecutor) { long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0; - + //构建key,用于缓存策略和请求 EngineKey key = keyFactory.buildKey( model, @@ -187,9 +188,11 @@ public LoadStatus load( EngineResource memoryResource; synchronized (this) { + //根据 key 拿到活动缓存,内存缓存中的资源 memoryResource = loadFromMemory(key, isMemoryCacheable, startTime); if (memoryResource == null) { + //等待现有工作或开始新工作 return waitForExistingOrStartNewJob( glideContext, model, @@ -215,13 +218,13 @@ public LoadStatus load( } } - // Avoid calling back while holding the engine lock, doing so makes it easier for callers to - // deadlock. + // Avoid calling back while holding the engine lock, doing so makes it easier for callers to deadlock. + // 缓存中有资源返回 cb.onResourceReady( memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false); return null; } - + // TODO: Glide源码-into流程 private LoadStatus waitForExistingOrStartNewJob( GlideContext glideContext, Object model, @@ -244,9 +247,10 @@ private LoadStatus waitForExistingOrStartNewJob( Executor callbackExecutor, EngineKey key, long startTime) { - + //根据 Key 看看缓存中是否正在执行 EngineJob current = jobs.get(key, onlyRetrieveFromCache); if (current != null) { + //如果正在执行,把数据回调出去 current.addCallback(cb, callbackExecutor); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Added to existing load", startTime, key); @@ -254,6 +258,8 @@ private LoadStatus waitForExistingOrStartNewJob( return new LoadStatus(cb, current); } + // -------------- 走到这里说明是一个新的任务 --------------- + // -------------- 构建新的请求任务 --------------- EngineJob engineJob = engineJobFactory.build( key, @@ -261,7 +267,7 @@ private LoadStatus waitForExistingOrStartNewJob( useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache); - + //构造decodeJob实现了runnable,放到engineJob中执行 DecodeJob decodeJob = decodeJobFactory.build( glideContext, @@ -280,10 +286,11 @@ private LoadStatus waitForExistingOrStartNewJob( onlyRetrieveFromCache, options, engineJob); - + //把当前需要执行的引擎工作添加到集合中 jobs.put(key, engineJob); - + //添加回调 engineJob.addCallback(cb, callbackExecutor); + //开始执行。 engineJob.start(decodeJob); if (VERBOSE_IS_LOGGABLE) { @@ -292,13 +299,14 @@ private LoadStatus waitForExistingOrStartNewJob( return new LoadStatus(cb, engineJob); } + // TODO: Glide源码-into流程 @Nullable private EngineResource loadFromMemory( EngineKey key, boolean isMemoryCacheable, long startTime) { if (!isMemoryCacheable) { return null; } - + // 从活动缓存中获取资源 EngineResource active = loadFromActiveResources(key); if (active != null) { if (VERBOSE_IS_LOGGABLE) { @@ -306,7 +314,7 @@ private EngineResource loadFromMemory( } return active; } - + // 从内存缓存中获取资源--如果内存缓存中有取出并从内存缓存中删除,放入活动缓存 EngineResource cached = loadFromCache(key); if (cached != null) { if (VERBOSE_IS_LOGGABLE) { @@ -333,9 +341,12 @@ private EngineResource loadFromActiveResources(Key key) { } private EngineResource loadFromCache(Key key) { + //从内存中取出,调用的remove方法 EngineResource cached = getEngineResourceFromCache(key); if (cached != null) { + //引用计数++ cached.acquire(); + //放入活动缓存 activeResources.activate(key, cached); } return cached; @@ -368,13 +379,15 @@ public void release(Resource resource) { @SuppressWarnings("unchecked") @Override + // TODO: Glide源码-into流程 public synchronized void onEngineJobComplete( EngineJob engineJob, Key key, EngineResource resource) { // A null resource indicates that the load failed, usually due to an exception. + //收到下游返回回来的资源,添加到活动缓存中 if (resource != null && resource.isMemoryCacheable()) { activeResources.activate(key, resource); } - + //删除任务 jobs.removeIfCurrent(key, engineJob); } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java b/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java index 33151e0746..389e9156f7 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java @@ -124,11 +124,18 @@ synchronized EngineJob init( this.onlyRetrieveFromCache = onlyRetrieveFromCache; return this; } - + // TODO: Glide源码-into流程 public synchronized void start(DecodeJob decodeJob) { this.decodeJob = decodeJob; GlideExecutor executor = + //RESOURCE_CACHE或DATA_CACHE使用diskCacheExecutor 本地缓存线程池 + //否则使用ActiveSourceExecutor decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); + //开始执行 + /** + * 通过 DecodeJob 源码得知,它是实现的 Runnable 接口,这里 GlideExecutor 线程池开始执行, + * 就会启动 DecodeJob 的 run 函数,我们跟踪 run 的实现。 + */ executor.execute(decodeJob); } @@ -151,11 +158,13 @@ synchronized void addCallback(final ResourceCallback cb, Executor callbackExecut @SuppressWarnings("WeakerAccess") @Synthetic @GuardedBy("this") + // TODO: Glide源码-into流程 void callCallbackOnResourceReady(ResourceCallback cb) { try { // This is overly broad, some Glide code is actually called here, but it's much // simpler to encapsulate here than to do so at the actual call point in the // Request implementation. + //回调给 SingleRequest cb.onResourceReady(engineResource, dataSource, isLoadedFromAlternateCacheKey); } catch (Throwable t) { throw new CallbackException(t); @@ -225,6 +234,7 @@ private boolean isDone() { "PMD.AvoidInstantiatingObjectsInLoops", "PMD.AccessorMethodGeneration" }) + // TODO: Glide源码-into流程 @Synthetic void notifyCallbacksOfResult() { ResourceCallbacksAndExecutors copy; @@ -255,10 +265,11 @@ void notifyCallbacksOfResult() { localKey = key; localResource = engineResource; } - + //回调上层 Engine 任务完成了 engineJobListener.onEngineJobComplete(this, localKey, localResource); - + //遍历资源回调给 ImageViewTarget for (final ResourceCallbackAndExecutor entry : copy) { + //进入CallResourceReady的run entry.executor.execute(new CallResourceReady(entry.cb)); } decrementPendingCallbacks(); @@ -314,6 +325,7 @@ private synchronized void release() { } @Override + // TODO: Glide源码-into流程 public void onResourceReady( Resource resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) { synchronized (this) { @@ -321,6 +333,7 @@ public void onResourceReady( this.dataSource = dataSource; this.isLoadedFromAlternateCacheKey = isLoadedFromAlternateCacheKey; } + //这 notifyCallbacksOfResult(); } @@ -333,6 +346,7 @@ public void onLoadFailed(GlideException e) { } @Override + // TODO: Glide源码-into流程 public void reschedule(DecodeJob job) { // Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself // up. @@ -417,6 +431,7 @@ private class CallResourceReady implements Runnable { } @Override + // TODO: Glide源码-into流程 public void run() { // Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock // (b/136032534). @@ -425,6 +440,7 @@ public void run() { if (cbs.contains(cb)) { // Acquire for this particular callback. engineResource.acquire(); + //返回准备好的资源 callCallbackOnResourceReady(cb); removeCallback(cb); } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/LoadPath.java b/library/src/main/java/com/bumptech/glide/load/engine/LoadPath.java index d3003642d8..1d71b11633 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/LoadPath.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/LoadPath.java @@ -44,7 +44,7 @@ public LoadPath( + transcodeClass.getSimpleName() + "}"; } - + // TODO: Glide源码-into流程-解析资源 public Resource load( DataRewinder rewinder, @NonNull Options options, @@ -54,12 +54,13 @@ public Resource load( throws GlideException { List throwables = Preconditions.checkNotNull(listPool.acquire()); try { + //这里 return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables); } finally { listPool.release(throwables); } } - + // TODO: Glide源码-into流程-解析资源 private Resource loadWithExceptionList( DataRewinder rewinder, @NonNull Options options, @@ -70,9 +71,11 @@ private Resource loadWithExceptionList( throws GlideException { Resource result = null; //noinspection ForLoopReplaceableByForEach to improve perf + //遍历内部存储的 DecodePath 集合,通过他们来解析数据 for (int i = 0, size = decodePaths.size(); i < size; i++) { DecodePath path = decodePaths.get(i); try { + //这里才是真正解析数据的地方 result = path.decode(rewinder, width, height, options, decodeCallback); } catch (GlideException e) { exceptions.add(e); diff --git a/library/src/main/java/com/bumptech/glide/load/engine/ResourceCacheGenerator.java b/library/src/main/java/com/bumptech/glide/load/engine/ResourceCacheGenerator.java index 425d19e0d6..22a1639da0 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/ResourceCacheGenerator.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/ResourceCacheGenerator.java @@ -41,6 +41,7 @@ class ResourceCacheGenerator implements DataFetcherGenerator, DataFetcher.DataCa // See TODO below. @SuppressWarnings("PMD.CollapsibleIfStatements") @Override + // TODO: Glide源码-into流程 public boolean startNext() { GlideTrace.beginSection("ResourceCacheGenerator.startNext"); try { @@ -85,9 +86,11 @@ public boolean startNext() { transformation, resourceClass, helper.getOptions()); + //从磁盘缓存中获取 cacheFile = helper.getDiskCache().get(currentKey); if (cacheFile != null) { sourceKey = sourceId; + //根据文件类型从注册组件里获取类型加载器 modelLoaders = helper.getModelLoaders(cacheFile); modelLoaderIndex = 0; } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java b/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java index 5273df49d0..bd6c2f205b 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java @@ -48,11 +48,13 @@ class SourceGenerator implements DataFetcherGenerator, DataFetcherGenerator.Fetc // Concurrent access isn't supported. @SuppressWarnings({"NonAtomicOperationOnVolatileField", "NonAtomicVolatileUpdate"}) @Override + // TODO: Glide源码-into流程 public boolean startNext() { if (dataToCache != null) { Object data = dataToCache; dataToCache = null; try { + //写入磁盘缓存 boolean isDataInCache = cacheData(data); // If we failed to write the data to cache, the cacheData method will try to decode the // original data directly instead of going through the disk cache. Since cacheData has @@ -71,7 +73,7 @@ public boolean startNext() { } } } - + //如果命中DataCacheGenerator直接返回 if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) { return true; } @@ -80,6 +82,8 @@ public boolean startNext() { loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { + //获取一个 ModelLoad 加载器--这里是 HttpGlideUrlLoader.buildLoadData获取 + //new LoadData<>(url, new HttpUrlFetcher(url, timeout)) loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource()) @@ -92,9 +96,11 @@ public boolean startNext() { } private void startNextLoad(final LoadData toStart) { + //使用加载器中的 fetcher 根据优先级加载数据HttpUrlFetcher->loadData()方法 loadData.fetcher.loadData( helper.getPriority(), new DataCallback() { + //从HttpUrlFetcher回调回来-data:InputStream @Override public void onDataReady(@Nullable Object data) { if (isCurrentRequest(toStart)) { @@ -138,6 +144,7 @@ private boolean cacheData(Object dataToCache) throws IOException { DataCacheWriter writer = new DataCacheWriter<>(encoder, data, helper.getOptions()); DataCacheKey newOriginalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature()); DiskCache diskCache = helper.getDiskCache(); + //写入DataCache缓存 diskCache.put(newOriginalKey, writer); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v( @@ -173,6 +180,7 @@ private boolean cacheData(Object dataToCache) throws IOException { } isLoadingFromSourceData = true; + //回调出去 cb.onDataFetcherReady( loadData.sourceKey, rewinder.rewindAndGet(), @@ -201,12 +209,14 @@ public void cancel() { @Synthetic void onDataReadyInternal(LoadData loadData, Object data) { DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy(); + //这里会走 else 因为我们没有配置缓存,继续回调。 if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) { dataToCache = data; // We might be being called back on someone else's thread. Before doing anything, we should // reschedule to get back onto Glide's thread. cb.reschedule(); } else { + //DecodeJob回调 cb.onDataFetcherReady( loadData.sourceKey, data, diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java index 866aaa15d8..3ff1a86fbb 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java @@ -59,6 +59,7 @@ public Resource decode( MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream); UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream); try { + // 根据请求配置来对数据进行采样压缩,获取一个 Resource return downsampler.decode(invalidatingStream, width, height, options, callbacks); } finally { exceptionStream.release(); diff --git a/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java b/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java index 96d536da74..5a2d8ff0c6 100644 --- a/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java +++ b/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java @@ -35,9 +35,12 @@ public class RequestTracker { private boolean isPaused; /** Starts tracking the given request. */ + // TODO: Glide源码-into流程 public void runRequest(@NonNull Request request) { requests.add(request); if (!isPaused) { + //没有暂停,开始调用 Request begin 执行 + //这里调用的是SignalRequest.begin request.begin(); } else { request.clear(); diff --git a/library/src/main/java/com/bumptech/glide/request/SingleRequest.java b/library/src/main/java/com/bumptech/glide/request/SingleRequest.java index 7025f6e700..66eef0fb80 100644 --- a/library/src/main/java/com/bumptech/glide/request/SingleRequest.java +++ b/library/src/main/java/com/bumptech/glide/request/SingleRequest.java @@ -212,6 +212,7 @@ private SingleRequest( } @Override + // TODO: Glide源码-into流程 public void begin() { synchronized (requestLock) { assertNotCallingCallbacks(); @@ -240,6 +241,7 @@ public void begin() { // that the view size has changed will need to explicitly clear the View or Target before // starting the new load. if (status == Status.COMPLETE) { + //表示资源准备好了 onResourceReady( resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false); return; @@ -250,14 +252,20 @@ public void begin() { cookie = GlideTrace.beginSectionAsync(TAG); status = Status.WAITING_FOR_SIZE; + //这里表示大小已经准备好了 if (Util.isValidDimensions(overrideWidth, overrideHeight)) { + + //开始 onSizeReady(overrideWidth, overrideHeight); } else { + //获取size,ViewTarget中获取,获取后会调用cb.onSizeReady(),即该类的onSizeReady() target.getSize(this); } + //这里是刚刚开始执行的回调,相当于显示开始的进度 if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged()) { + //显示占位图 target.onLoadStarted(getPlaceholderDrawable()); } if (IS_VERBOSE_LOGGABLE) { @@ -432,9 +440,11 @@ private void setErrorPlaceholder() { } /** A callback method that should never be invoked directly. */ + // TODO: Glide源码-into流程 @Override public void onSizeReady(int width, int height) { stateVerifier.throwIfRecycled(); + //都是一些初始化状态,配置属性,我们不用管。 synchronized (requestLock) { if (IS_VERBOSE_LOGGABLE) { logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime)); @@ -452,6 +462,7 @@ public void onSizeReady(int width, int height) { logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime)); } loadStatus = + //引擎加载 engine.load( glideContext, model, @@ -526,6 +537,7 @@ private void notifyLoadFailed() { /** A callback method that should never be invoked directly. */ @SuppressWarnings("unchecked") @Override + // TODO: Glide源码-into流程 public void onResourceReady( Resource resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) { stateVerifier.throwIfRecycled(); @@ -579,7 +591,7 @@ public void onResourceReady( GlideTrace.endSectionAsync(TAG, cookie); return; } - + //当资源准备好的时候 onResourceReady( (Resource) resource, (R) received, dataSource, isLoadedFromAlternateCacheKey); } @@ -601,6 +613,7 @@ public void onResourceReady( // We're using experimental APIs... @SuppressWarnings({"deprecation", "PMD.UnusedFormalParameter"}) @GuardedBy("requestLock") + // TODO: Glide源码-into流程 private void onResourceReady( Resource resource, R result, DataSource dataSource, boolean isAlternateCacheKey) { // We must call isFirstReadyResource before setting status. @@ -641,12 +654,13 @@ private void onResourceReady( if (!anyListenerHandledUpdatingTarget) { Transition animation = animationFactory.build(dataSource, isFirstResource); + //回调给目标 ImageViewTarget 资源准备好了 target.onResourceReady(result, animation); } } finally { isCallingCallbacks = false; } - + //加载成功 notifyLoadSuccess(); GlideTrace.endSectionAsync(TAG, cookie); } diff --git a/library/src/main/java/com/bumptech/glide/request/target/ImageViewTarget.java b/library/src/main/java/com/bumptech/glide/request/target/ImageViewTarget.java index ce53193f77..4fe34fb4ae 100644 --- a/library/src/main/java/com/bumptech/glide/request/target/ImageViewTarget.java +++ b/library/src/main/java/com/bumptech/glide/request/target/ImageViewTarget.java @@ -96,8 +96,10 @@ public void onLoadCleared(@Nullable Drawable placeholder) { } @Override + // TODO: Glide源码-into流程 public void onResourceReady(@NonNull Z resource, @Nullable Transition transition) { if (transition == null || !transition.transition(resource, this)) { + //这 setResourceInternal(resource); } else { maybeUpdateAnimatable(resource); @@ -117,10 +119,11 @@ public void onStop() { animatable.stop(); } } - + // TODO: Glide源码-into流程 private void setResourceInternal(@Nullable Z resource) { // Order matters here. Set the resource first to make sure that the Drawable has a valid and // non-null Callback before starting it. + //DrawableImageViewTarget 设置给imageview setResource(resource); maybeUpdateAnimatable(resource); } From ffbd75b877d32984243670044bbbe56501b0c8b1 Mon Sep 17 00:00:00 2001 From: lishuai Date: Wed, 3 Nov 2021 17:35:53 +0800 Subject: [PATCH 6/9] =?UTF-8?q?glide.into-=E7=BD=91=E7=BB=9C=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E8=B5=84=E6=BA=90=E5=88=B0=E7=A3=81=E7=9B=98=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E7=9A=84=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bumptech/glide/load/engine/EngineJob.java | 1 + .../glide/load/engine/SourceGenerator.java | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java b/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java index 389e9156f7..41a9aa9458 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java @@ -258,6 +258,7 @@ void notifyCallbacksOfResult() { // middle of notifying if it synchronously released by one of the callbacks. Acquire it under // a lock here so that any newly added callback that executes before the next locked section // below can't recycle the resource before we call the callbacks. + //hasResource标为true hasResource = true; copy = cbs.copy(); incrementPendingCallbacks(copy.size() + 1); diff --git a/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java b/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java index bd6c2f205b..4500ec7ca7 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java @@ -22,8 +22,8 @@ * using registered {@link com.bumptech.glide.load.model.ModelLoader ModelLoaders} and the model * provided for the load. * - *

Depending on the disk cache strategy, source data may first be written to disk and then loaded - * from the cache file rather than returned directly. + *

Depending on the disk cache strategy, source data may first be written to disk and then + * loaded from the cache file rather than returned directly. * *

This object may be used by multiple threads, but only one at a time. It is not safe to access * this object on multiple threads concurrently. @@ -50,6 +50,7 @@ class SourceGenerator implements DataFetcherGenerator, DataFetcherGenerator.Fetc @Override // TODO: Glide源码-into流程 public boolean startNext() { + //重新走进来后进行缓存 if (dataToCache != null) { Object data = dataToCache; dataToCache = null; @@ -87,7 +88,7 @@ public boolean startNext() { loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource()) - || helper.hasLoadPath(loadData.fetcher.getDataClass()))) { + || helper.hasLoadPath(loadData.fetcher.getDataClass()))) { started = true; startNextLoad(loadData); } @@ -134,6 +135,12 @@ private boolean hasNextModelLoader() { * directly from cache and {@code false} if we were unable to cache the data and should make an * attempt to decode from source. */ + /** + * 缓存成功则从缓存中取数据进行解码,如果缓存失败则直接回调出去源数据进行解码 + * @param dataToCache + * @return + * @throws IOException + */ private boolean cacheData(Object dataToCache) throws IOException { long startTime = LogTime.getLogTime(); boolean isLoadingFromSourceData = false; @@ -159,7 +166,7 @@ private boolean cacheData(Object dataToCache) throws IOException { + ", duration: " + LogTime.getElapsedMillis(startTime)); } - + //磁盘缓存中有此key,说明缓存成功,创建磁盘缓存处理器,从磁盘缓存中获取 if (diskCache.get(newOriginalKey) != null) { originalKey = newOriginalKey; sourceCacheGenerator = @@ -180,7 +187,7 @@ private boolean cacheData(Object dataToCache) throws IOException { } isLoadingFromSourceData = true; - //回调出去 + //没有就回调出去 cb.onDataFetcherReady( loadData.sourceKey, rewinder.rewindAndGet(), @@ -209,11 +216,12 @@ public void cancel() { @Synthetic void onDataReadyInternal(LoadData loadData, Object data) { DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy(); - //这里会走 else 因为我们没有配置缓存,继续回调。 + //如果有配置磁盘缓存走这里,没有走else if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) { dataToCache = data; // We might be being called back on someone else's thread. Before doing anything, we should // reschedule to get back onto Glide's thread. + //重新切换线程池,重新走进该类里 cb.reschedule(); } else { //DecodeJob回调 From 9c9e8de4d5e86ad133f0a03eab8b9bdfcf6b1c16 Mon Sep 17 00:00:00 2001 From: lis Date: Wed, 3 Nov 2021 23:05:11 +0800 Subject: [PATCH 7/9] =?UTF-8?q?glide.into=E6=B5=81=E7=A8=8B=EF=BC=8C?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E7=BC=93=E5=AD=98=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/bumptech/glide/load/engine/DataCacheGenerator.java | 1 + .../src/main/java/com/bumptech/glide/load/model/FileLoader.java | 1 + 2 files changed, 2 insertions(+) diff --git a/library/src/main/java/com/bumptech/glide/load/engine/DataCacheGenerator.java b/library/src/main/java/com/bumptech/glide/load/engine/DataCacheGenerator.java index e39ef688c1..0dc1aa5dd4 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/DataCacheGenerator.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/DataCacheGenerator.java @@ -76,6 +76,7 @@ public boolean startNext() { cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions()); if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) { started = true; + //从File转换成Stream--FileOpener loadData.fetcher.loadData(helper.getPriority(), this); } } diff --git a/library/src/main/java/com/bumptech/glide/load/model/FileLoader.java b/library/src/main/java/com/bumptech/glide/load/model/FileLoader.java index 379ce351fe..2693c5c515 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/FileLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/FileLoader.java @@ -68,6 +68,7 @@ private static final class FileFetcher implements DataFetcher { @Override public void loadData(@NonNull Priority priority, @NonNull DataCallback callback) { try { + //从File到InputStream,调用StreamFactory.open data = opener.open(file); callback.onDataReady(data); } catch (FileNotFoundException e) { From 500e9a7b395c2a1a76f8ac6587a0d1b687c7b475 Mon Sep 17 00:00:00 2001 From: lishuai Date: Tue, 9 Nov 2021 16:17:01 +0800 Subject: [PATCH 8/9] =?UTF-8?q?glide.into-=E7=BC=96=E8=A7=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8CResourceDisk=E7=BC=93=E5=AD=98=E7=9A=84=E6=97=B6?= =?UTF-8?q?=E6=9C=BA=E6=98=AF=E5=9C=A8=E8=A7=A3=E7=A0=81=E5=90=8E=EF=BC=8C?= =?UTF-8?q?=E5=9B=9E=E8=B0=83DecodeJob.onResourceDecoded=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=8C=E5=AF=B9source=E8=BF=9B=E8=A1=8Ctransform=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=90=8E=EF=BC=8C=E8=BF=9B=E8=A1=8C=E7=9A=84=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E6=98=AF=E5=90=A6=E9=9C=80=E8=A6=81=E7=BC=93=E5=AD=98?= =?UTF-8?q?=EF=BC=8C=E8=A7=A3=E6=9E=90=E5=AE=8C=E5=90=8E=EF=BC=8C=E8=B0=83?= =?UTF-8?q?=E7=94=A8notifyEncodeAndRelease=EF=BC=8C=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E5=88=B0=E6=B4=BB=E5=8A=A8=E7=BC=93=E5=AD=98?= =?UTF-8?q?=EF=BC=8C=E5=8A=A0=E8=BD=BD=E5=88=B0ResourceDisk=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bumptech/glide/load/engine/DecodeJob.java | 76 ++++++++++++++----- .../glide/load/engine/DecodePath.java | 3 +- .../glide/load/engine/SourceGenerator.java | 5 +- .../engine/cache/MemorySizeCalculator.java | 2 +- .../glide/load/model/StreamEncoder.java | 1 + .../load/resource/bitmap/BitmapEncoder.java | 5 ++ 6 files changed, 68 insertions(+), 24 deletions(-) diff --git a/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java b/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java index 902958bf4f..0bb500caaa 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java @@ -33,13 +33,13 @@ *

Note: this class has a natural ordering that is inconsistent with equals. * * @param The type of resource that will be transcoded from the decoded and transformed - * resource. + * resource. */ class DecodeJob implements DataFetcherGenerator.FetcherReadyCallback, - Runnable, - Comparable>, - Poolable { + Runnable, + Comparable>, + Poolable { private static final String TAG = "DecodeJob"; private final DecodeHelper decodeHelper = new DecodeHelper<>(); @@ -145,7 +145,7 @@ boolean willDecodeFromCache() { * Called when this object is no longer in use externally. * * @param isRemovedFromQueue {@code true} if we've been removed from the queue and {@link #run} is - * neither in progress nor will ever be called again. + * neither in progress nor will ever be called again. */ void release(boolean isRemovedFromQueue) { if (releaseManager.release(isRemovedFromQueue)) { @@ -163,7 +163,9 @@ private void onEncodeComplete() { } } - /** Called when the load has failed due to a an error or a series of errors. */ + /** + * Called when the load has failed due to a an error or a series of errors. + */ private void onLoadFailed() { if (releaseManager.onFailed()) { releaseInternal(); @@ -271,6 +273,7 @@ public void run() { GlideTrace.endSection(); } } + // TODO: Glide源码-into流程 private void runWrapped() { switch (runReason) { @@ -282,7 +285,7 @@ private void runWrapped() { //执行 Generator runGenerators(); break; - //切换线程池后重新执行这里 + //切换线程池后重新执行这里 case SWITCH_TO_SOURCE_SERVICE: runGenerators(); break; @@ -308,6 +311,7 @@ private DataFetcherGenerator getNextGenerator() { throw new IllegalStateException("Unrecognized stage: " + stage); } } + // TODO: Glide源码-into流程 private void runGenerators() { currentThread = Thread.currentThread(); @@ -345,6 +349,7 @@ private void notifyFailed() { callback.onLoadFailed(e); onLoadFailed(); } + // TODO: Glide源码-into流程 private void notifyComplete( Resource resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) { @@ -382,6 +387,7 @@ private Stage getNextStage(Stage current) { throw new IllegalArgumentException("Unrecognized stage: " + current); } } + // TODO: Glide源码-into流程 @Override public void reschedule() { @@ -400,7 +406,7 @@ public void onDataFetcherReady( this.currentDataSource = dataSource;//数据来源 url this.currentAttemptingKey = attemptedKey; this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0); - //线程不一致时会通过回调返回 + //线程不一致时切换线程池重新执行DecodeJob的run()方法再调用 decodeFromRetrievedData()方法。 if (Thread.currentThread() != currentThread) { runReason = RunReason.DECODE_DATA; callback.reschedule(this); @@ -429,7 +435,8 @@ public void onDataFetcherFailed( runGenerators(); } } - // TODO: Glide源码-into流程 + + // TODO: Glide源码-into流程--返回数据 private void decodeFromRetrievedData() { if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey( @@ -444,7 +451,7 @@ private void decodeFromRetrievedData() { } Resource resource = null; try { - // 调用 decodeFrom 解析 数据;HttpUrlFetcher , InputStream , currentDataSource + // 调用 decodeFrom 解析 数据;HttpUrlFetcher , InputStream , DataSource.REMOTE resource = decodeFromData(currentFetcher, currentData, currentDataSource); } catch (GlideException e) { e.setLoggingDetails(currentAttemptingKey, currentDataSource); @@ -457,6 +464,7 @@ private void decodeFromRetrievedData() { runGenerators(); } } + // TODO: Glide源码-into流程 private void notifyEncodeAndRelease( Resource resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) { @@ -477,7 +485,7 @@ private void notifyEncodeAndRelease( stage = Stage.ENCODE; try { - //这里就是将资源磁盘缓存 + //这里就是Resource磁盘缓存 if (deferredEncodeManager.hasResourceToEncode()) { deferredEncodeManager.encode(diskCacheProvider, options); } @@ -495,6 +503,7 @@ private void notifyEncodeAndRelease( GlideTrace.endSection(); } } + // TODO: Glide源码-into流程-解析资源 private Resource decodeFromData( DataFetcher fetcher, Data data, DataSource dataSource) throws GlideException { @@ -549,6 +558,7 @@ private Options getOptionsWithHardwareConfig(DataSource dataSource) { return options; } + // TODO: Glide源码-into流程-解析资源 private Resource runLoadPath( Data data, DataSource dataSource, LoadPath path) @@ -597,8 +607,10 @@ Resource onResourceDecoded(DataSource dataSource, @NonNull Resource de Class resourceSubClass = (Class) decoded.get().getClass(); Transformation appliedTransformation = null; Resource transformed = decoded; + //如果不是Resource缓存 if (dataSource != DataSource.RESOURCE_DISK_CACHE) { appliedTransformation = decodeHelper.getTransformation(resourceSubClass); + //执行 transform transformed = appliedTransformation.transform(glideContext, decoded, width, height); } // TODO: Make this the responsibility of the Transformation. @@ -618,6 +630,7 @@ Resource onResourceDecoded(DataSource dataSource, @NonNull Resource de Resource result = transformed; boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey); + //是否Resource磁盘缓存 if (diskCacheStrategy.isResourceCacheable( isFromAlternateCacheKey, dataSource, encodeStrategy)) { if (encoder == null) { @@ -728,6 +741,7 @@ void init(Key key, ResourceEncoder encoder, LockedResource toEncode) { void encode(DiskCacheProvider diskCacheProvider, Options options) { GlideTrace.beginSection("DecodeJob.encode"); try { + //磁盘缓存 diskCacheProvider .getDiskCache() .put(key, new DataCacheWriter<>(encoder, toEncode, options)); @@ -762,11 +776,17 @@ interface DiskCacheProvider { DiskCache getDiskCache(); } - /** Why we're being executed again. */ + /** + * Why we're being executed again. + */ private enum RunReason { - /** The first time we've been submitted. */ + /** + * The first time we've been submitted. + */ INITIALIZE, - /** We want to switch from the disk cache service to the source executor. */ + /** + * We want to switch from the disk cache service to the source executor. + */ SWITCH_TO_SOURCE_SERVICE, /** * We retrieved some data on a thread we don't own and want to switch back to our thread to @@ -775,19 +795,33 @@ private enum RunReason { DECODE_DATA, } - /** Where we're trying to decode data from. */ + /** + * Where we're trying to decode data from. + */ private enum Stage { - /** The initial stage. */ + /** + * The initial stage. + */ INITIALIZE, - /** Decode from a cached resource. */ + /** + * Decode from a cached resource. + */ RESOURCE_CACHE, - /** Decode from cached source data. */ + /** + * Decode from cached source data. + */ DATA_CACHE, - /** Decode from retrieved source. */ + /** + * Decode from retrieved source. + */ SOURCE, - /** Encoding transformed resources after a successful load. */ + /** + * Encoding transformed resources after a successful load. + */ ENCODE, - /** No more viable stages. */ + /** + * No more viable stages. + */ FINISHED, } } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/DecodePath.java b/library/src/main/java/com/bumptech/glide/load/engine/DecodePath.java index 4ae7a761aa..dc27ac6e4c 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/DecodePath.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/DecodePath.java @@ -94,7 +94,8 @@ private Resource decodeResourceWithList( DataType data = rewinder.rewindAndGet(); if (decoder.handles(data, options)) { data = rewinder.rewindAndGet(); - // 调用 ResourceDrawableDecoder.decode 解析数据StreamBitmapDecoder + //如果从磁盘缓存调用 + // 调用 StreamBitmapDecoder.decode 解析数据 StreamBitmapDecoder result = decoder.decode(data, width, height, options); } // Some decoders throw unexpectedly. If they do, we shouldn't fail the entire load path, but diff --git a/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java b/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java index 4500ec7ca7..7533e00e3b 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/SourceGenerator.java @@ -60,6 +60,7 @@ public boolean startNext() { // If we failed to write the data to cache, the cacheData method will try to decode the // original data directly instead of going through the disk cache. Since cacheData has // already called our callback at this point, there's nothing more to do but return. + //这里在cacheData()中写入磁盘失败的时候通过DecodeJob.onDataFetcherReady()回调出去了,按命中返回true if (!isDataInCache) { return true; } @@ -74,7 +75,7 @@ public boolean startNext() { } } } - //如果命中DataCacheGenerator直接返回 + //写入磁盘缓存成功后,执行DataCacheGenerator.startNext()策略,如果命中这里也返回true,表示命中 if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) { return true; } @@ -82,6 +83,7 @@ public boolean startNext() { loadData = null; boolean started = false; + //循环加载器 while (!started && hasNextModelLoader()) { //获取一个 ModelLoad 加载器--这里是 HttpGlideUrlLoader.buildLoadData获取 //new LoadData<>(url, new HttpUrlFetcher(url, timeout)) @@ -93,6 +95,7 @@ public boolean startNext() { startNextLoad(loadData); } } + //否则返回false表示未命中 return started; } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java b/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java index 2783765789..a706e9c632 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java @@ -34,7 +34,7 @@ interface ScreenDimensions { // Package private to avoid PMD warning. MemorySizeCalculator(MemorySizeCalculator.Builder builder) { this.context = builder.context; - + //默认4M,低内存2M arrayPoolSize = isLowMemoryDevice(builder.activityManager) ? builder.arrayPoolSizeBytes / LOW_MEMORY_BYTE_ARRAY_POOL_DIVISOR diff --git a/library/src/main/java/com/bumptech/glide/load/model/StreamEncoder.java b/library/src/main/java/com/bumptech/glide/load/model/StreamEncoder.java index 1a6bc462eb..4e53c4f79c 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/StreamEncoder.java +++ b/library/src/main/java/com/bumptech/glide/load/model/StreamEncoder.java @@ -23,6 +23,7 @@ public StreamEncoder(ArrayPool byteArrayPool) { } @Override + //InputStream->File public boolean encode(@NonNull InputStream data, @NonNull File file, @NonNull Options options) { byte[] buffer = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class); boolean success = false; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoder.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoder.java index 4f948c28f6..608486e842 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoder.java @@ -63,14 +63,17 @@ public BitmapEncoder() { } @Override + //Bitmap->File public boolean encode( @NonNull Resource resource, @NonNull File file, @NonNull Options options) { final Bitmap bitmap = resource.get(); + //压缩格式CompressFormat,无透明度JPEG,有透明度PNG Bitmap.CompressFormat format = getFormat(bitmap, options); GlideTrace.beginSectionFormat( "encode: [%dx%d] %s", bitmap.getWidth(), bitmap.getHeight(), format); try { long start = LogTime.getLogTime(); + //压缩质量0-100,默认90 int quality = options.get(COMPRESSION_QUALITY); boolean success = false; @@ -118,6 +121,7 @@ public boolean encode( } private Bitmap.CompressFormat getFormat(Bitmap bitmap, Options options) { + //压缩格式CompressFormat,无透明度JPEG,有透明度PNG Bitmap.CompressFormat format = options.get(COMPRESSION_FORMAT); if (format != null) { return format; @@ -131,6 +135,7 @@ private Bitmap.CompressFormat getFormat(Bitmap bitmap, Options options) { @NonNull @Override public EncodeStrategy getEncodeStrategy(@NonNull Options options) { + //将资源的解码、下采样和转换数据写入磁盘。 return EncodeStrategy.TRANSFORMED; } } From 5e611a9c67249f81e99af7dcc6c4f42041bd60c4 Mon Sep 17 00:00:00 2001 From: lishuai Date: Thu, 18 Nov 2021 23:23:07 +0800 Subject: [PATCH 9/9] =?UTF-8?q?1.Glide=E7=94=9F=E5=91=BD=E5=91=A8=E6=9C=9F?= =?UTF-8?q?=E5=8F=98=E5=8C=96=E6=97=B6=EF=BC=8C=E7=9A=84=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=202.BitmapPool=E7=9B=B8=E5=85=B3=203.Downsam?= =?UTF-8?q?pler=E4=B8=AD=E8=BD=ACBitmap=E6=93=8D=E4=BD=9C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/bumptech/glide/Glide.java | 1 + .../java/com/bumptech/glide/GlideBuilder.java | 1 + .../com/bumptech/glide/RequestManager.java | 20 ++++++- .../bumptech/glide/load/engine/Engine.java | 8 ++- .../glide/load/engine/EngineResource.java | 3 + .../glide/load/engine/ResourceRecycler.java | 5 +- .../bitmap_recycle/AttributeStrategy.java | 1 + .../engine/bitmap_recycle/LruBitmapPool.java | 60 +++++++++++++++---- .../bitmap_recycle/SizeConfigStrategy.java | 1 + .../engine/cache/MemorySizeCalculator.java | 32 ++++++---- .../load/resource/bitmap/Downsampler.java | 23 +++++-- .../resource/bitmap/StreamBitmapDecoder.java | 1 + .../manager/ActivityFragmentLifecycle.java | 9 ++- .../glide/manager/RequestTracker.java | 5 ++ .../SupportRequestManagerFragment.java | 8 ++- .../bumptech/glide/request/SingleRequest.java | 7 ++- .../java/com/bumptech/glide/util/Util.java | 47 +++++++++++---- 17 files changed, 185 insertions(+), 47 deletions(-) diff --git a/library/src/main/java/com/bumptech/glide/Glide.java b/library/src/main/java/com/bumptech/glide/Glide.java index 5d2119be97..67a0a85179 100644 --- a/library/src/main/java/com/bumptech/glide/Glide.java +++ b/library/src/main/java/com/bumptech/glide/Glide.java @@ -423,6 +423,7 @@ private static void throwIncorrectGlideModule(Exception e) { VideoDecoder.parcel(bitmapPool); // TODO(judds): Make ParcelFileDescriptorBitmapDecoder work with ImageDecoder. + //文件,流等转Bitmap操作 Downsampler downsampler = new Downsampler( registry.getImageHeaderParsers(), resources.getDisplayMetrics(), bitmapPool, arrayPool); diff --git a/library/src/main/java/com/bumptech/glide/GlideBuilder.java b/library/src/main/java/com/bumptech/glide/GlideBuilder.java index 41373766ba..76ae5c7a97 100644 --- a/library/src/main/java/com/bumptech/glide/GlideBuilder.java +++ b/library/src/main/java/com/bumptech/glide/GlideBuilder.java @@ -520,6 +520,7 @@ Glide build(@NonNull Context context) { if (bitmapPool == null) { int size = memorySizeCalculator.getBitmapPoolSize(); if (size > 0) { + //TODO BitmapPool-图片缓存池 bitmapPool = new LruBitmapPool(size); } else { bitmapPool = new BitmapPoolAdapter(); diff --git a/library/src/main/java/com/bumptech/glide/RequestManager.java b/library/src/main/java/com/bumptech/glide/RequestManager.java index d67dd20ab5..c11a1d66f3 100644 --- a/library/src/main/java/com/bumptech/glide/RequestManager.java +++ b/library/src/main/java/com/bumptech/glide/RequestManager.java @@ -255,6 +255,7 @@ public synchronized boolean isPaused() { * @see #isPaused() * @see #resumeRequests() */ + // TODO Glide生命周期变化时调用-onStop() public synchronized void pauseRequests() { requestTracker.pauseRequests(); } @@ -323,6 +324,8 @@ public synchronized void pauseRequestsRecursive() { * @see #isPaused() * @see #pauseRequests() */ + // TODO Glide生命周期变化时调用-onStart() + public synchronized void resumeRequests() { requestTracker.resumeRequests(); } @@ -347,9 +350,12 @@ public synchronized void resumeRequestsRecursive() { * android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused * requests. */ + // TODO Glide生命周期变化时调用-onStart() @Override public synchronized void onStart() { + //开始请求 resumeRequests(); + //开启动画用 targetTracker.onStart(); } @@ -357,9 +363,12 @@ public synchronized void onStart() { * Lifecycle callback that unregisters for connectivity events (if the * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads. */ + // TODO Glide生命周期变化时调用-onStop() @Override public synchronized void onStop() { + //停止 pauseRequests(); + //停止动画用 targetTracker.onStop(); } @@ -367,17 +376,22 @@ public synchronized void onStop() { * Lifecycle callback that cancels all in progress requests and clears and recycles resources for * all completed requests. */ + // TODO Glide生命周期变化时调用-onDestroy() @Override public synchronized void onDestroy() { targetTracker.onDestroy(); for (Target target : targetTracker.getAll()) { + //clear每个target,会调用request.clear() clear(target); } targetTracker.clear(); + //从Requests中移除request,也,会调用request.clear() requestTracker.clearRequests(); + //移除监听 lifecycle.removeListener(this); lifecycle.removeListener(connectivityMonitor); Util.removeCallbacksOnUiThread(addSelfToLifecycle); + //glide移除RequestManager glide.unregisterRequestManager(this); } @@ -625,6 +639,7 @@ public void clear(@NonNull View view) { * * @param target The Target to cancel loads for. */ + // TODO Glide生命周期变化时调用-onDestroy() public void clear(@Nullable final Target target) { if (target == null) { return; @@ -632,7 +647,7 @@ public void clear(@Nullable final Target target) { untrackOrDelegate(target); } - + // TODO Glide生命周期变化时调用-onDestroy() private void untrackOrDelegate(@NonNull Target target) { boolean isOwnedByUs = untrack(target); // We'll end up here if the Target was cleared after the RequestManager that started the request @@ -655,6 +670,7 @@ private void untrackOrDelegate(@NonNull Target target) { Request request = target.getRequest(); if (!isOwnedByUs && !glide.removeFromManagers(target) && request != null) { target.setRequest(null); + //调用request.clear(),和Stop流程一致 request.clear(); } } @@ -667,7 +683,9 @@ synchronized boolean untrack(@NonNull Target target) { } if (requestTracker.clearAndRemove(request)) { + //target移除 targetTracker.untrack(target); + //target移除request,imageview的Tag设置为null target.setRequest(null); return true; } else { diff --git a/library/src/main/java/com/bumptech/glide/load/engine/Engine.java b/library/src/main/java/com/bumptech/glide/load/engine/Engine.java index c945b9e8a3..cacb9dca83 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/Engine.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/Engine.java @@ -368,9 +368,10 @@ private EngineResource getEngineResourceFromCache(Key key) { } return result; } - + // TODO Glide生命周期变化时调用-onStop() public void release(Resource resource) { if (resource instanceof EngineResource) { + //活动到内存 ((EngineResource) resource).release(); } else { throw new IllegalArgumentException("Cannot release anything but an EngineResource"); @@ -403,12 +404,17 @@ public void onResourceRemoved(@NonNull final Resource resource) { resourceRecycler.recycle(resource, /*forceNextFrame=*/ true); } + // TODO Glide生命周期变化时调用-onStop() @Override public void onResourceReleased(Key cacheKey, EngineResource resource) { + //活动缓存删除 activeResources.deactivate(cacheKey); + //支持内存缓存 if (resource.isMemoryCacheable()) { + //放入内存缓存 cache.put(cacheKey, resource); } else { + //不支持的话,释放 resourceRecycler.recycle(resource, /*forceNextFrame=*/ false); } } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/EngineResource.java b/library/src/main/java/com/bumptech/glide/load/engine/EngineResource.java index 1bbc821a46..6138d89248 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/EngineResource.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/EngineResource.java @@ -102,17 +102,20 @@ synchronized void acquire() { */ // listener is effectively final. @SuppressWarnings("SynchronizeOnNonFinalField") + // TODO Glide生命周期变化时调用-onStop() void release() { boolean release = false; synchronized (this) { if (acquired <= 0) { throw new IllegalStateException("Cannot release a recycled or not yet acquired resource"); } + //为0表示活动缓存没有使用的地方了 if (--acquired == 0) { release = true; } } if (release) { + //活动到内存 listener.onResourceReleased(key, this); } } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/ResourceRecycler.java b/library/src/main/java/com/bumptech/glide/load/engine/ResourceRecycler.java index ed26e67ca4..81a2a367e1 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/ResourceRecycler.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/ResourceRecycler.java @@ -11,14 +11,17 @@ class ResourceRecycler { private final Handler handler = new Handler(Looper.getMainLooper(), new ResourceRecyclerCallback()); + // TODO Glide生命周期变化时调用-onStop() synchronized void recycle(Resource resource, boolean forceNextFrame) { + //正在释放或有子资源,发送handler进行释放 if (isRecycling || forceNextFrame) { - // If a resource has sub-resources, releasing a sub resource can cause it's parent to be + // If a resource has sub-resources, releasing a sub resource can cause it's parent to be synchronously evicted which leads to a recycle loop when the parent releases it's children. // synchronously evicted which leads to a recycle loop when the parent releases it's children. // Posting breaks this loop. handler.obtainMessage(ResourceRecyclerCallback.RECYCLE_RESOURCE, resource).sendToTarget(); } else { isRecycling = true; + //释放-bitmap的话使用BitmapResource放在BitmapPool resource.recycle(); isRecycling = false; } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/AttributeStrategy.java b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/AttributeStrategy.java index 896b13f838..9d10612d8d 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/AttributeStrategy.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/AttributeStrategy.java @@ -64,6 +64,7 @@ static String getBitmapString(int width, int height, Bitmap.Config config) { @VisibleForTesting static class KeyPool extends BaseKeyPool { + Key get(int width, int height, Bitmap.Config config) { Key result = get(); result.init(width, height, config); diff --git a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java index 8ebf35628d..197ca387ef 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java @@ -25,6 +25,9 @@ public class LruBitmapPool implements BitmapPool { private static final String TAG = "LruBitmapPool"; private static final Bitmap.Config DEFAULT_CONFIG = Bitmap.Config.ARGB_8888; + /** + * 策略模式 + */ private final LruPoolStrategy strategy; private final Set allowedConfigs; private final long initialMaxSize; @@ -51,6 +54,7 @@ public class LruBitmapPool implements BitmapPool { * * @param maxSize The initial maximum size of the pool in bytes. */ + //在GlideBuilder中创建时设置的大小 public LruBitmapPool(long maxSize) { this(maxSize, getDefaultStrategy(), getDefaultAllowedConfigs()); } @@ -58,9 +62,10 @@ public LruBitmapPool(long maxSize) { /** * Constructor for LruBitmapPool. * - * @param maxSize The initial maximum size of the pool in bytes. + * @param maxSize The initial maximum size of the pool in bytes. * @param allowedConfigs A white listed put of {@link android.graphics.Bitmap.Config} that are - * allowed to be put into the pool. Configs not in the allowed put will be rejected. + * allowed to be put into the pool. Configs not in the allowed put will be + * rejected. */ // Public API. @SuppressWarnings("unused") @@ -68,22 +73,30 @@ public LruBitmapPool(long maxSize, Set allowedConfigs) { this(maxSize, getDefaultStrategy(), allowedConfigs); } - /** Returns the number of cache hits for bitmaps in the pool. */ + /** + * Returns the number of cache hits for bitmaps in the pool. + */ public long hitCount() { return hits; } - /** Returns the number of cache misses for bitmaps in the pool. */ + /** + * Returns the number of cache misses for bitmaps in the pool. + */ public long missCount() { return misses; } - /** Returns the number of bitmaps that have been evicted from the pool. */ + /** + * Returns the number of bitmaps that have been evicted from the pool. + */ public long evictionCount() { return evictions; } - /** Returns the current size of the pool in bytes. */ + /** + * Returns the current size of the pool in bytes. + */ public long getCurrentSize() { return currentSize; } @@ -99,6 +112,7 @@ public synchronized void setSizeMultiplier(float sizeMultiplier) { evict(); } + //图片放入LruBitmapPool @Override public synchronized void put(Bitmap bitmap) { if (bitmap == null) { @@ -124,22 +138,29 @@ public synchronized void put(Bitmap bitmap) { bitmap.recycle(); return; } - + //获取图片大小 final int size = strategy.getSize(bitmap); strategy.put(bitmap); + //用于调试不用管 tracker.add(bitmap); + //添加的数量++ puts++; + //总使用内存的大小 currentSize += size; if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Put bitmap in pool=" + strategy.logBitmap(bitmap)); } + //debug会 dump(); evict(); } + /** + * 判断内存是否需要移除了 + */ private void evict() { trimToSize(maxSize); } @@ -152,8 +173,10 @@ public Bitmap get(int width, int height, Bitmap.Config config) { // Bitmaps in the pool contain random data that in some cases must be cleared for an image // to be rendered correctly. we shouldn't force all consumers to independently erase the // contents individually, so we do so here. See issue #131. + //擦除位图中的数据 result.eraseColor(Color.TRANSPARENT); } else { + //创建位图 result = createBitmap(width, height, config); } @@ -197,6 +220,7 @@ private synchronized Bitmap getDirtyOrNull( assertNotHardwareConfig(config); // Config will be null for non public config types, which can lead to transformations naively // passing in null as the requested config here. See issue #194. + //策略中获取位图 final Bitmap result = strategy.get(width, height, config != null ? config : DEFAULT_CONFIG); if (result == null) { if (Log.isLoggable(TAG, Log.DEBUG)) { @@ -205,6 +229,7 @@ private synchronized Bitmap getDirtyOrNull( misses++; } else { hits++; + //更新总大小 currentSize -= strategy.getSize(result); tracker.remove(result); normalize(result); @@ -217,8 +242,10 @@ private synchronized Bitmap getDirtyOrNull( return result; } - // Setting these two values provides Bitmaps that are essentially equivalent to those returned - // from Bitmap.createBitmap. + /** + * Setting these two values provides Bitmaps that are essentially equivalent to those returned from Bitmap.createBitmap. + * @param bitmap + */ private static void normalize(Bitmap bitmap) { bitmap.setHasAlpha(true); maybeSetPreMultiplied(bitmap); @@ -247,7 +274,7 @@ public void trimMemory(int level) { } if ((level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) || ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - && (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN))) { + && (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN))) { clearMemory(); } else if ((level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) || (level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL)) { @@ -256,7 +283,9 @@ public void trimMemory(int level) { } private synchronized void trimToSize(long size) { + //当前使用内存大于最大内存了 while (currentSize > size) { + //移除尾部 final Bitmap removed = strategy.removeLast(); // TODO: This shouldn't ever happen, see #331. if (removed == null) { @@ -264,16 +293,19 @@ private synchronized void trimToSize(long size) { Log.w(TAG, "Size mismatch, resetting"); dumpUnchecked(); } + //BitmapPool为空了 currentSize = 0; return; } tracker.remove(removed); + //减去尾部位图的大小 currentSize -= strategy.getSize(removed); evictions++; if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Evicting bitmap=" + strategy.logBitmap(removed)); } dump(); + //位图回收 removed.recycle(); } } @@ -303,8 +335,14 @@ private void dumpUnchecked() { + strategy); } + /** + * 默认策略 + * + * @return + */ private static LruPoolStrategy getDefaultStrategy() { final LruPoolStrategy strategy; + //大于等于19,4.4时使用SizeConfigStrategy,之前使用AttributeStrategy if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { strategy = new SizeConfigStrategy(); } else { @@ -313,7 +351,7 @@ private static LruPoolStrategy getDefaultStrategy() { return strategy; } - @TargetApi(Build.VERSION_CODES.O) + @TargetApi(Build.VERSION_CODES.O)//8.0 private static Set getDefaultAllowedConfigs() { Set configs = new HashSet<>(Arrays.asList(Bitmap.Config.values())); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { diff --git a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/SizeConfigStrategy.java b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/SizeConfigStrategy.java index 992d41ddf2..5a6c413fb6 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/SizeConfigStrategy.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/SizeConfigStrategy.java @@ -74,6 +74,7 @@ public void put(Bitmap bitmap) { @Override @Nullable public Bitmap get(int width, int height, Bitmap.Config config) { + //获取Bitmap的大小 int size = Util.getBitmapByteSize(width, height, config); Key bestKey = findBestKey(size, config); diff --git a/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java b/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java index a706e9c632..90b2884a6e 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java @@ -39,17 +39,19 @@ interface ScreenDimensions { isLowMemoryDevice(builder.activityManager) ? builder.arrayPoolSizeBytes / LOW_MEMORY_BYTE_ARRAY_POOL_DIVISOR : builder.arrayPoolSizeBytes; + //大内存设备0.4的堆大小,小内存则0.3的堆大小 int maxSize = - getMaxSize( + getMaxSize(//activityManager,0.4f,0.3f builder.activityManager, builder.maxSizeMultiplier, builder.lowMemoryMaxSizeMultiplier); int widthPixels = builder.screenDimensions.getWidthPixels(); int heightPixels = builder.screenDimensions.getHeightPixels(); int screenSize = widthPixels * heightPixels * BYTES_PER_ARGB_8888_PIXEL; - + //一屏的大小(长*宽*4)*bitmapPoolScreens(26前为4,26和26后为1) int targetBitmapPoolSize = Math.round(screenSize * builder.bitmapPoolScreens); - + //一屏大小 * 2 int targetMemoryCacheSize = Math.round(screenSize * builder.memoryCacheScreens); + //可用大小=最大大小-数组池大小 int availableSize = maxSize - arrayPoolSize; if (targetMemoryCacheSize + targetBitmapPoolSize <= availableSize) { @@ -82,24 +84,32 @@ interface ScreenDimensions { } } - /** Returns the recommended memory cache size for the device it is run on in bytes. */ + /** + * Returns the recommended memory cache size for the device it is run on in bytes. + */ public int getMemoryCacheSize() { return memoryCacheSize; } - /** Returns the recommended bitmap pool size for the device it is run on in bytes. */ + /** + * Returns the recommended bitmap pool size for the device it is run on in bytes. + */ public int getBitmapPoolSize() { return bitmapPoolSize; } - /** Returns the recommended array pool size for the device it is run on in bytes. */ + /** + * Returns the recommended array pool size for the device it is run on in bytes. + */ public int getArrayPoolSizeInBytes() { return arrayPoolSize; } private static int getMaxSize( ActivityManager activityManager, float maxSizeMultiplier, float lowMemoryMaxSizeMultiplier) { + //堆大小(M)*1024(K)*1024(Byte) final int memoryClassBytes = activityManager.getMemoryClass() * 1024 * 1024; + //1G或更小的设备为小内存设备 final boolean isLowMemoryDevice = isLowMemoryDevice(activityManager); return Math.round( memoryClassBytes * (isLowMemoryDevice ? lowMemoryMaxSizeMultiplier : maxSizeMultiplier)); @@ -172,9 +182,8 @@ public Builder(Context context) { } /** - * Sets the number of device screens worth of pixels the {@link - * com.bumptech.glide.load.engine.cache.MemoryCache} should be able to hold and returns this - * Builder. + * Sets the number of device screens worth of pixels the {@link com.bumptech.glide.load.engine.cache.MemoryCache} + * should be able to hold and returns this Builder. */ public Builder setMemoryCacheScreens(float memoryCacheScreens) { Preconditions.checkArgument( @@ -184,9 +193,8 @@ public Builder setMemoryCacheScreens(float memoryCacheScreens) { } /** - * Sets the number of device screens worth of pixels the {@link - * com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} should be able to hold and returns - * this Builder. + * Sets the number of device screens worth of pixels the {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} + * should be able to hold and returns this Builder. */ public Builder setBitmapPoolScreens(float bitmapPoolScreens) { Preconditions.checkArgument( diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java index 2a1a85e6d7..0094915427 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java @@ -212,6 +212,7 @@ public Resource decode( * @return A new bitmap containing the image from the given InputStream, or recycle if recycle is * not null. */ + //从StreamBitmapDecoder中解析时调用到这里 public Resource decode( InputStream is, int requestedWidth, @@ -279,7 +280,7 @@ private Resource decode( boolean fixBitmapToRequestedDimensions = options.get(FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS); boolean isHardwareConfigAllowed = options.get(ALLOW_HARDWARE_CONFIG) != null && options.get(ALLOW_HARDWARE_CONFIG); - + //最终都是这在这个方法中转换成Bitmap的 decodeFromWrappedStreams try { Bitmap result = decodeFromWrappedStreams( @@ -300,6 +301,7 @@ private Resource decode( } } + // TODO: 2021/11/18 转换成Bitmap关键类 private Bitmap decodeFromWrappedStreams( ImageReader imageReader, BitmapFactory.Options options, @@ -313,7 +315,7 @@ private Bitmap decodeFromWrappedStreams( DecodeCallbacks callbacks) throws IOException { long startTime = LogTime.getLogTime(); - + // 通过设置 inJustDecodeBounds 读取图片的原始尺寸信息 int[] sourceDimensions = getDimensions(imageReader, options, callbacks, bitmapPool); int sourceWidth = sourceDimensions[0]; int sourceHeight = sourceDimensions[1]; @@ -327,6 +329,7 @@ private Bitmap decodeFromWrappedStreams( isHardwareConfigAllowed = false; } + // 读取图片的 exif 信息,如果需要的话,先对图片进行旋转 int orientation = imageReader.getImageOrientation(); int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation); boolean isExifOrientationRequired = TransformationUtils.isExifOrientationRequired(orientation); @@ -341,7 +344,7 @@ private Bitmap decodeFromWrappedStreams( : requestedHeight; ImageType imageType = imageReader.getImageType(); - + // 根据要求计算需要记载的图片大小和 config,计算结果直接设置给 options 即可 calculateScaling( imageType, imageReader, @@ -408,6 +411,7 @@ private Bitmap decodeFromWrappedStreams( } // If this isn't an image, or BitmapFactory was unable to parse the size, width and height // will be -1 here. + // 根据图片的期望尺寸到 BitmapPool 中获取一个 Bitmap 以复用 if (expectedWidth > 0 && expectedHeight > 0) { setInBitmap(options, bitmapPool, expectedWidth, expectedHeight); } @@ -425,7 +429,7 @@ private Bitmap decodeFromWrappedStreams( options.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB); } } - +// 开始执行 decode 逻辑 Bitmap downsampled = decodeStream(imageReader, options, callbacks, bitmapPool); callbacks.onDecodeComplete(bitmapPool, downsampled); @@ -441,6 +445,7 @@ private Bitmap decodeFromWrappedStreams( startTime); } + // ... 图片旋转等后续逻辑 Bitmap rotated = null; if (downsampled != null) { // If we scaled, the Bitmap density will be our inTargetDensity. Here we correct it back to @@ -778,8 +783,15 @@ private static Bitmap decodeStream( final Bitmap result; TransformationUtils.getBitmapDrawableLock().lock(); try { + // 数据加载 result = imageReader.decodeBitmap(options); } catch (IllegalArgumentException e) { + // TODO: Glide 首先会通过设置 inBitmap 复用的方式加载图片。 + // 如果这个过程中出现了异常,因为此时 inBitmap 不为空,所以将会进入异常处理流程,此 + // 时会清理掉 inBitmap,再次调用 decodeStream 方法二次加载,这个时候就不是 Bitmap 复用的了。 + // 所以,Glide 内部会通过错误重试机制进行 Bitmap 复用,当复用并出现错误的时候,会降级为非复用的方式第二次进行加载。 + //作者:shouheng + //链接:https://juejin.cn/post/6951585628890857480 IOException bitmapAssertionException = newIoExceptionForInBitmapAssertion(e, sourceWidth, sourceHeight, outMimeType, options); if (Log.isLoggable(TAG, Log.DEBUG)) { @@ -790,8 +802,11 @@ private static Bitmap decodeStream( } if (options.inBitmap != null) { try { + // TODO: 2021/11/18 这里没看到 is.reset(); 输入流重置。而是使用了ImageReader bitmapPool.put(options.inBitmap); + // 清理掉 inBitmap 并进行第二次加载 options.inBitmap = null; + // 再次调用进行加载 return decodeStream(imageReader, options, callbacks, bitmapPool); } catch (IOException resetException) { throw bitmapAssertionException; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java index 3ff1a86fbb..9b8497b0aa 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java @@ -60,6 +60,7 @@ public Resource decode( UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream); try { // 根据请求配置来对数据进行采样压缩,获取一个 Resource + //Downsampler.decode中解析 return downsampler.decode(invalidatingStream, width, height, options, callbacks); } finally { exceptionStream.release(); diff --git a/library/src/main/java/com/bumptech/glide/manager/ActivityFragmentLifecycle.java b/library/src/main/java/com/bumptech/glide/manager/ActivityFragmentLifecycle.java index 120278c594..7c111de643 100644 --- a/library/src/main/java/com/bumptech/glide/manager/ActivityFragmentLifecycle.java +++ b/library/src/main/java/com/bumptech/glide/manager/ActivityFragmentLifecycle.java @@ -44,24 +44,27 @@ public void addListener(@NonNull LifecycleListener listener) { public void removeListener(@NonNull LifecycleListener listener) { lifecycleListeners.remove(listener); } - + // TODO Glide生命周期变化时调用-onStart() void onStart() { isStarted = true; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { + //这里跳转到RequestManager的onStart()方法 lifecycleListener.onStart(); } } - + // TODO Glide生命周期变化时调用-onStop() void onStop() { isStarted = false; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { + //这里跳转到RequestManager的 onStop()方法 lifecycleListener.onStop(); } } - + // TODO Glide生命周期变化时调用-onDestroy() void onDestroy() { isDestroyed = true; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { + //这里跳转到RequestManager的 onDestroy()方法 lifecycleListener.onDestroy(); } } diff --git a/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java b/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java index 5a2d8ff0c6..c5968281f1 100644 --- a/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java +++ b/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java @@ -81,6 +81,7 @@ public boolean isPaused() { } /** Stops any in progress requests. */ + // TODO Glide生命周期变化时调用-onStop() public void pauseRequests() { isPaused = true; for (Request request : Util.getSnapshot(requests)) { @@ -88,6 +89,7 @@ public void pauseRequests() { // Avoid clearing parts of requests that may have completed (thumbnails) to avoid blinking // in the UI, while still making sure that any in progress parts of requests are immediately // stopped. + //request停止操作 SingleRequest request.pause(); pendingRequests.add(request); } @@ -106,6 +108,8 @@ public void pauseAllRequests() { } /** Starts any not yet completed or failed requests. */ + // TODO Glide生命周期变化时调用-onStart() + public void resumeRequests() { isPaused = false; for (Request request : Util.getSnapshot(requests)) { @@ -113,6 +117,7 @@ public void resumeRequests() { // Request from the tracker, so the only way we'd find a cleared request here is if we cleared // it. As a result it should be safe for us to resume cleared requests. if (!request.isComplete() && !request.isRunning()) { + //开始begin()--后续流程和into流程一致 request.begin(); } } diff --git a/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java b/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java index fe558d4d02..83f8be693b 100644 --- a/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java +++ b/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java @@ -197,22 +197,28 @@ public void onDetach() { unregisterFragmentWithRoot(); } + // TODO Glide生命周期变化时调用-onStart() @Override public void onStart() { super.onStart(); + //调用到ActivityFragmentLifecycle中 lifecycle.onStart(); } + // TODO Glide生命周期变化时调用-onStop() @Override public void onStop() { super.onStop(); + //调用到ActivityFragmentLifecycle中 lifecycle.onStop(); } - + // TODO Glide生命周期变化时调用-onDestroy() @Override public void onDestroy() { super.onDestroy(); + //调用到ActivityFragmentLifecycle中 lifecycle.onDestroy(); + //fragment的释放 unregisterFragmentWithRoot(); } diff --git a/library/src/main/java/com/bumptech/glide/request/SingleRequest.java b/library/src/main/java/com/bumptech/glide/request/SingleRequest.java index 66eef0fb80..6e51d217aa 100644 --- a/library/src/main/java/com/bumptech/glide/request/SingleRequest.java +++ b/library/src/main/java/com/bumptech/glide/request/SingleRequest.java @@ -313,6 +313,8 @@ private void assertNotCallingCallbacks() { * * @see #cancel() */ + // TODO Glide生命周期变化时调用-onStop() + // TODO Glide生命周期变化时调用-onDestroy() @Override public void clear() { Resource toRelease = null; @@ -335,16 +337,19 @@ public void clear() { GlideTrace.endSectionAsync(TAG, cookie); status = Status.CLEARED; } - + //图片资源释放 if (toRelease != null) { + //活动到内存 engine.release(toRelease); } } @Override + // TODO Glide生命周期变化时调用-onStop() public void pause() { synchronized (requestLock) { if (isRunning()) { + //clear操作 clear(); } } diff --git a/library/src/main/java/com/bumptech/glide/util/Util.java b/library/src/main/java/com/bumptech/glide/util/Util.java index eb81dc1ae1..7509e4d702 100644 --- a/library/src/main/java/com/bumptech/glide/util/Util.java +++ b/library/src/main/java/com/bumptech/glide/util/Util.java @@ -15,7 +15,9 @@ import java.util.List; import java.util.Queue; -/** A collection of assorted utility classes. */ +/** + * A collection of assorted utility classes. + */ public final class Util { private static final int HASH_MULTIPLIER = 31; private static final int HASH_ACCUMULATOR = 17; @@ -28,7 +30,9 @@ private Util() { // Utility class. } - /** Returns the hex string of the given byte array representing a SHA256 hash. */ + /** + * Returns the hex string of the given byte array representing a SHA256 hash. + */ @NonNull public static String sha256BytesToHex(@NonNull byte[] bytes) { synchronized (SHA_256_CHARS) { @@ -56,14 +60,16 @@ private static String bytesToHex(@NonNull byte[] bytes, @NonNull char[] hexChars * * @see #getBitmapByteSize(android.graphics.Bitmap) * @deprecated Use {@link #getBitmapByteSize(android.graphics.Bitmap)} instead. Scheduled to be - * removed in Glide 4.0. + * removed in Glide 4.0. */ @Deprecated public static int getSize(@NonNull Bitmap bitmap) { return getBitmapByteSize(bitmap); } - /** Returns the in memory size of the given {@link Bitmap} in bytes. */ + /** + * Returns the in memory size of the given {@link Bitmap} in bytes. + */ @TargetApi(Build.VERSION_CODES.KITKAT) public static int getBitmapByteSize(@NonNull Bitmap bitmap) { // The return value of getAllocationByteCount silently changes for recycled bitmaps from the @@ -83,13 +89,16 @@ public static int getBitmapByteSize(@NonNull Bitmap bitmap) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Workaround for KitKat initial release NPE in Bitmap, fixed in MR1. See issue #148. try { + //>=4.4时,获取原始位图大小,getByteCount()当前大小。原始位图复用或修改config配置后 + //getAllocationByteCount()有可能大于getByteCount() return bitmap.getAllocationByteCount(); } catch ( @SuppressWarnings("PMD.AvoidCatchingNPE") - NullPointerException e) { + NullPointerException e) { // Do nothing. } } + //4.4前通过高*行获取 return bitmap.getHeight() * bitmap.getRowBytes(); } @@ -127,7 +136,9 @@ private static int getBytesPerPixel(@Nullable Bitmap.Config config) { return bytesPerPixel; } - /** Returns true if width and height are both > 0 and/or equal to {@link Target#SIZE_ORIGINAL}. */ + /** + * Returns true if width and height are both > 0 and/or equal to {@link Target#SIZE_ORIGINAL}. + */ public static boolean isValidDimensions(int width, int height) { return isValidDimension(width) && isValidDimension(height); } @@ -136,12 +147,16 @@ private static boolean isValidDimension(int dimen) { return dimen > 0 || dimen == Target.SIZE_ORIGINAL; } - /** Posts the given {@code runnable} to the UI thread using a shared {@link Handler}. */ + /** + * Posts the given {@code runnable} to the UI thread using a shared {@link Handler}. + */ public static void postOnUiThread(Runnable runnable) { getUiThreadHandler().post(runnable); } - /** Removes the given {@code runnable} from the UI threads queue if it is still queued. */ + /** + * Removes the given {@code runnable} from the UI threads queue if it is still queued. + */ public static void removeCallbacksOnUiThread(Runnable runnable) { getUiThreadHandler().removeCallbacks(runnable); } @@ -167,24 +182,32 @@ public static void assertMainThread() { } } - /** Throws an {@link java.lang.IllegalArgumentException} if called on the main thread. */ + /** + * Throws an {@link java.lang.IllegalArgumentException} if called on the main thread. + */ public static void assertBackgroundThread() { if (!isOnBackgroundThread()) { throw new IllegalArgumentException("You must call this method on a background thread"); } } - /** Returns {@code true} if called on the main thread, {@code false} otherwise. */ + /** + * Returns {@code true} if called on the main thread, {@code false} otherwise. + */ public static boolean isOnMainThread() { return Looper.myLooper() == Looper.getMainLooper(); } - /** Returns {@code true} if called on a background thread, {@code false} otherwise. */ + /** + * Returns {@code true} if called on a background thread, {@code false} otherwise. + */ public static boolean isOnBackgroundThread() { return !isOnMainThread(); } - /** Creates a {@link java.util.Queue} of the given size using Glide's preferred implementation. */ + /** + * Creates a {@link java.util.Queue} of the given size using Glide's preferred implementation. + */ @NonNull public static Queue createQueue(int size) { return new ArrayDeque<>(size);