<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          錦囊篇|一文摸懂Glide

          共 19989字,需瀏覽 40分鐘

           ·

          2020-07-11 11:23

          d437b3747939d5bb0b3dabad8382cfbe.webp前言

          和之前的文章會(huì)有一定的不同,這主要是因?yàn)?code style="font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:#e46918;background-color:#efefef;font-size:.875em;">Glide自身的源碼量導(dǎo)致的問(wèn)題,因?yàn)槲沂亲詈髮?xiě)的前言,你會(huì)發(fā)現(xiàn)在文章剛開(kāi)始時(shí)會(huì)代碼復(fù)制的比較完全,后面就比較零散,而且一部分我直接用自己話去進(jìn)行了表述。如果真的要看懂,建議還是對(duì)著Glide的源碼進(jìn)行查看,這樣會(huì)幫助你更好去理解GLide的它的實(shí)現(xiàn)流程。

          使用方法

          (1)資源引入

          repositories {
          mavenCentral()
          google()
          }

          dependencies {
          implementation 'com.github.bumptech.glide:glide:4.11.0'
          annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
          }

          (2)方法使用

          // 實(shí)現(xiàn)單張圖片加載
          @Override public void onCreate(Bundle savedInstanceState) {
          ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
          // 如果是最新版的系統(tǒng)是不允許http來(lái)進(jìn)行請(qǐng)求的
          // 去百度隨便拿一張圖片的地址來(lái)改一下就好了
          Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
          }

          // 實(shí)現(xiàn)圖片列表加載
          @Override public View getView(int position, View recycled, ViewGroup container) {
          final ImageView myImageView;
          if (recycled == null) {
          myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
          } else {
          myImageView = (ImageView) recycled;
          }

          String url = myUrls.get(position);

          Glide
          .with(myFragment)
          .load(url)
          .centerCrop()
          .placeholder(R.drawable.loading_spinner)
          .into(myImageView);

          return myImageView;
          }
          源碼分析

          在源碼使用中,其實(shí)基礎(chǔ)的在上面的使用方法中已經(jīng)講述到了,一共可以分為三個(gè)步驟:

          1. with(Context)
          2. load(ImageURL)
          3. into(ImageView)

          我們的分析流程也將圍繞這三個(gè)函數(shù)來(lái)進(jìn)行展開(kāi)。

          with(Context)

            @NonNull
          public static RequestManager with(@NonNull Context context) {
          return getRetriever(context).get(context);
          }

          @NonNull
          public static RequestManager with(@NonNull Activity activity) {
          return getRetriever(activity).get(activity);
          }

          @NonNull
          public static RequestManager with(@NonNull FragmentActivity activity) {
          return getRetriever(activity).get(activity);
          }

          @NonNull
          public static RequestManager with(@NonNull Fragment fragment) {
          return getRetriever(fragment.getContext()).get(fragment);
          }

          @SuppressWarnings("deprecation")
          @Deprecated
          @NonNull
          public static RequestManager with(@NonNull android.app.Fragment fragment) {
          return getRetriever(fragment.getActivity()).get(fragment);
          }

          @NonNull
          public static RequestManager with(@NonNull View view) {
          return getRetriever(view.getContext()).get(view);
          }

          悄咪咪數(shù)了數(shù),Oh my Gosh?。?! 竟然高達(dá)有6個(gè)重載方法。不過(guò)呢想必你也發(fā)現(xiàn)這些方法都直接調(diào)用了getRetriever().get()的方法,那目的就非常明顯了,我們進(jìn)到這個(gè)方法去一探究竟了。

            @NonNull
          private static RequestManagerRetriever getRetriever(@Nullable Context context) {
          return Glide.get(context).getRequestManagerRetriever(); // 1 -->
          }

          @NonNull
          public static Glide get(@NonNull Context context) {
          if (glide == null) {
          // 使用了context.getApplicationContext()是為了防止內(nèi)存泄漏的發(fā)生
          GeneratedAppGlideModule annotationGeneratedModule =
          getAnnotationGeneratedGlideModules(context.getApplicationContext());
          synchronized (Glide.class) {
          if (glide == null) {
          // 對(duì)glide整體地進(jìn)行初始化
          // 其中就包含了對(duì)RequestManagerRetriever的初始化流程
          // 代碼量比較大就不做介紹了
          checkAndInitializeGlide(context, annotationGeneratedModule);
          }
          }
          }
          return glide;
          }

          既然是一堆的初始化操作,最后我們的目標(biāo)又是RequestManagerRetriever這個(gè)類(lèi),那自然是有必要對(duì)這個(gè)類(lèi)進(jìn)行探究的。

          public class RequestManagerRetriever implements Handler.Callback {

          public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
          this.factory = factory != null ? factory : DEFAULT_FACTORY;
          handler = new Handler(Looper.getMainLooper(), this /* Callback */);
          }

          private static final RequestManagerFactory DEFAULT_FACTORY =
          new RequestManagerFactory() {
          @NonNull
          @Override
          public RequestManager build(
          @NonNull Glide glide,
          @NonNull Lifecycle lifecycle,
          @NonNull RequestManagerTreeNode requestManagerTreeNode,
          @NonNull Context context)
          {
          return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
          }
          };

          // getRetriever()的get()方法
          // 對(duì)標(biāo)上面的6個(gè)重載方法的調(diào)用,這里只取其一
          @NonNull
          public RequestManager get(@NonNull FragmentActivity activity) {
          // 如果當(dāng)前的線程是在后臺(tái)線程中,則進(jìn)入
          if (Util.isOnBackgroundThread()) {
          return get(activity.getApplicationContext()); // 1-->
          } else {
          assertNotDestroyed(activity);
          FragmentManager fm = activity.getSupportFragmentManager();
          return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); // 2 -->
          }
          }
          }

          (1)通過(guò)構(gòu)造函數(shù)我們能夠猜測(cè)的內(nèi)容是通信的工具是Handler,而Looper使用的是MainLooper也就是主線程的,那說(shuō)明最后異步通信也就直接扔到主線程完成了。

          (2)通過(guò)get()函數(shù),可以發(fā)現(xiàn)其實(shí)分為兩個(gè)部分。一是再一層的get()方法;二是supportFragmentGet()或者是FragmentGet()方法。

          他們最后的任務(wù)都是為了創(chuàng)建出一個(gè)RequestManager,但是我們得關(guān)注一下它的創(chuàng)建方式。

          get()

          對(duì)于這個(gè)方法而言就是對(duì)context的判定是否為Application,然后給出相應(yīng)的結(jié)果。

          (1)不是Application且是在主線程中時(shí)

          if (Util.isOnMainThread() && !(context instanceof Application)) {
          if (context instanceof FragmentActivity) {
          return get((FragmentActivity) context);
          } else if (context instanceof Activity) {
          return get((Activity) context);
          } else if (context instanceof ContextWrapper
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
          return get(((ContextWrapper) context).getBaseContext());
          }
          }

          而他們的歸宿,最后還是回到我們上方的重載方法。

          (2)是Application或是不再主線程時(shí)

          getApplicationManager(context); // 1 -->

          // 使用DCL的方式來(lái)創(chuàng)建了單例
          @NonNull
          private RequestManager getApplicationManager(@NonNull Context context) {
          // Either an application context or we're on a background thread.
          if (applicationManager == null) {
          synchronized (this) {
          if (applicationManager == null) {
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
          factory.build(
          glide,
          new ApplicationLifecycle(), // 2
          new EmptyRequestManagerTreeNode(),
          context.getApplicationContext());
          }
          }
          }
          return applicationManager;
          }

          通過(guò)工廠來(lái)自建了一個(gè)RequestManager,注釋2處他直接使用了ApplicationLifecycle原因是因?yàn)槟承┣闆r下會(huì)接受不到生命周期的事件,這里是做的強(qiáng)制性的操作是為了生命周期變化時(shí)能夠正常相應(yīng)。

          FragmentGet()

          瞟了一下,這是要一個(gè)廢棄的方法了,但是和supportFragmentGet()的方法相比其實(shí)也差不太多。

          private RequestManager fragmentGet(
          @NonNull Context context,
          @NonNull android.app.FragmentManager fm,
          @Nullable android.app.Fragment parentHint,
          boolean isParentVisible)
          {
          RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible); // 1 -->
          RequestManager requestManager = current.getRequestManager();
          if (requestManager == null) {
          // TODO(b/27524013): Factor out this Glide.get() call.
          Glide glide = Glide.get(context);
          requestManager =
          factory.build(
          glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
          // 將requestManager和Fragment相掛鉤
          // 用以完成生命周期的監(jiān)聽(tīng)
          current.setRequestManager(requestManager);
          }
          return requestManager;
          }

          // 1 -->
          // 獲取對(duì)應(yīng)的Fragment
          private RequestManagerFragment getRequestManagerFragment(
          @NonNull final android.app.FragmentManager fm,
          @Nullable android.app.Fragment parentHint,
          boolean isParentVisible)
          {
          // 尋找的方式是通過(guò)設(shè)置的TAG
          RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
          // 先去等待隊(duì)列中進(jìn)行查詢
          // 這一步的作用是防止Fragment的重復(fù)添加
          // 因?yàn)樘砑拥腇ragment的所謂的生命周期有一定的延時(shí)性
          if (current == null) {
          current = pendingRequestManagerFragments.get(fm);
          // 如果等待隊(duì)列創(chuàng)建一個(gè)新的TAG
          if (current == null) {
          current = new RequestManagerFragment();
          current.setParentFragmentHint(parentHint);
          if (isParentVisible) {
          current.getGlideLifecycle().onStart();
          }
          pendingRequestManagerFragments.put(fm, current);
          fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
          handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
          }
          }
          return current;
          }

          總結(jié)

          1. 初始化Glide的同時(shí)在內(nèi)部完成了RequestManagerRetriever的創(chuàng)建
          2. 獲取到的RequestManagerRetriever調(diào)用get()方法,獲取到RequestManager,獲取方式分為以下兩種:
          • ContextApplication時(shí), 通過(guò)getApplicationManager()方法創(chuàng)建RequestManager完成,將生命周期的監(jiān)聽(tīng)與Application強(qiáng)制綁定用于接收。
          • Context不為Application時(shí), 通過(guò)supportFragmentGet()方法創(chuàng)建RequestManager完成,生命周期的監(jiān)聽(tīng)是與Fragment進(jìn)行綁定實(shí)現(xiàn)。

          創(chuàng)建對(duì)應(yīng)TAG的一個(gè)非常直接的好處,我們的圖片像RecyclerView會(huì)放置中不容易出現(xiàn)錯(cuò)位的現(xiàn)象。

          load(ImageURL)

          總體來(lái)說(shuō)上面的就是一個(gè)初始化和必要變量獲取的操作,那接下從函數(shù)方法來(lái)看我們似乎是要去獲得的圖片了呢。

          public RequestBuilder load(@Nullable String string) {
          return asDrawable().load(string); // 1 -->
          }

          注釋1處,我們通過(guò)觀察可以知道他最后會(huì)選擇將獲取的數(shù)據(jù)轉(zhuǎn)化變成一個(gè)Drawable的類(lèi)然后再在我們對(duì)應(yīng)的ImageView上來(lái)進(jìn)行顯示。那我們就對(duì)asDrawable()先進(jìn)行一段源碼的分析。

          // asDrawable()不斷深入能發(fā)現(xiàn)調(diào)用到的函數(shù)
          // 是完成一個(gè)類(lèi)RequestBuilder的對(duì)象創(chuàng)建
          public RequestBuilder as(
          @NonNull Class resourceClass)
          { // Drawable.class
          return new RequestBuilder<>(glide, this, resourceClass, context);
          }

          那接下來(lái)的問(wèn)題就要進(jìn)入到這個(gè)類(lèi)中,因?yàn)樵谇懊嫖覀兊奶剿髌鋵?shí)算是并沒(méi)有什么收獲的,而如果只是創(chuàng)建一個(gè)類(lèi)顯然是不會(huì)讓這句話顯得這么重要,那關(guān)鍵點(diǎn)一定會(huì)出現(xiàn)在這個(gè)類(lèi)的構(gòu)造中了。

          protected RequestBuilder(
          @NonNull Glide glide,
          RequestManager requestManager,
          Class transcodeClass,
          Context context)
          {
          this.glide = glide;
          this.requestManager = requestManager;
          this.transcodeClass = transcodeClass;
          this.context = context;
          this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
          this.glideContext = glide.getGlideContext();

          initRequestListeners(requestManager.getDefaultRequestListeners()); // 1 -->
          // 這段代碼過(guò)長(zhǎng),不做展示,它的主要任務(wù)就是一些策略開(kāi)關(guān)
          // 各種選項(xiàng)的開(kāi)啟裝置,比如錯(cuò)誤提示、優(yōu)先級(jí)、磁盤(pán)緩存策略、固定寬高等等
          apply(requestManager.getDefaultRequestOptions());
          }

          // 1-->
          // 從某種意義上講就是對(duì)生命周期的監(jiān)聽(tīng)
          private void initRequestListeners(List> requestListeners) {
          for (RequestListener listener : requestListeners) {
          addListener((RequestListener) listener);
          }
          }

          而如果回到load(string)方法。

          private RequestBuilder loadGeneric(@Nullable Object model) {
          this.model = model;
          isModelSet = true;
          return this;
          }

          他最后的差事也就是將URI的值放到了model這個(gè)變量中,那整個(gè)load()函數(shù)作用其實(shí)最后只是創(chuàng)建了一個(gè)RequestBuilder的事例,那最后的獲取和加載工作肯定是在into()函數(shù)中才進(jìn)行了操作的。

          into(ImageView)

          public ViewTarget into(@NonNull ImageView view) {
          Util.assertMainThread();
          Preconditions.checkNotNull(view);

          BaseRequestOptions requestOptions = this;
          if (!requestOptions.isTransformationSet()
          && requestOptions.isTransformationAllowed()
          && view.getScaleType() != null) {
          // 通過(guò)scaleType,對(duì)圖片的屬性進(jìn)行設(shè)定
          switch (view.getScaleType()) {
          case CENTER_CROP:
          // 。。。。。。
          default:
          // Do nothing.
          }
          }
          // 正式將圖片數(shù)據(jù)塞入
          // 1 -->
          return into(
          // 2 -->
          glideContext.buildImageViewTarget(view, transcodeClass), // 深度調(diào)用可以知道也就是將View進(jìn)行了賦值
          /*targetListener=*/ null,
          requestOptions,
          // 能夠看到線程池的影子,后面的圖片的獲取和處理我們猜測(cè)就是通過(guò)池來(lái)進(jìn)行處理
          Executors.mainThreadExecutor());
          }

          // 1 --> 將數(shù)據(jù)塞入
          private > Y into(
          @NonNull Y target,
          @Nullable RequestListener targetListener,
          BaseRequestOptions options,
          Executor callbackExecutor)
          {
          // 正常情況構(gòu)建SingleRequest的請(qǐng)求
          // 因?yàn)閠humbnail一般需要額外的需求
          Request request = buildRequest(target, targetListener, options, callbackExecutor);

          Request previous = target.getRequest();
          // 當(dāng)前請(qǐng)求和最新的一樣
          if (request.isEquivalentTo(previous)
          && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
          // 如果請(qǐng)求完成,重新啟動(dòng)會(huì)保證結(jié)果送達(dá)并觸動(dòng)目標(biāo)
          // 如果請(qǐng)求失敗,會(huì)給出機(jī)會(huì)去再次完成
          // 如果請(qǐng)求正在運(yùn)行,不會(huì)打斷
          if (!Preconditions.checkNotNull(previous).isRunning()) {
          previous.begin();
          }
          return target;
          }

          requestManager.clear(target);
          target.setRequest(request); // 置換最新的請(qǐng)求
          requestManager.track(target, request); // 3 -->

          return target;
          }

          下面的內(nèi)容將主要對(duì)上述代碼中的注釋2和注釋3進(jìn)行講解。

          glideContext.buildImageViewTarget(view, transcodeClass)

          從字面意思,相比你也能夠進(jìn)行理解了,就是要構(gòu)建一個(gè)存放的目標(biāo)。

            @NonNull
          public ViewTarget buildImageViewTarget(
          @NonNull ImageView imageView, @NonNull Class transcodeClass)
          {
          return imageViewTargetFactory.buildTarget(imageView, transcodeClass); // 1 -->
          }

          // 1-->
          // 根據(jù)不同的數(shù)據(jù)類(lèi)型選擇存儲(chǔ)是以Drawable還是Bitmap構(gòu)建
          public ViewTarget buildTarget(
          @NonNull ImageView view, @NonNull Class clazz)
          {
          if (Bitmap.class.equals(clazz)) {
          // 以Bitmap構(gòu)建
          return (ViewTarget) new BitmapImageViewTarget(view); // 2-->
          } else if (Drawable.class.isAssignableFrom(clazz)) {
          // 以Drawable構(gòu)建
          return (ViewTarget) new DrawableImageViewTarget(view); // 2 -->
          } else {
          throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
          }
          }

          // 2-->
          // 兩個(gè)注釋最后深度調(diào)用之后都會(huì)調(diào)用到這段代碼
          // 如果單看這段代碼的時(shí)候其實(shí)
          public ViewTarget(@NonNull T view) {
          this.view = Preconditions.checkNotNull(view);
          // 如果只看這個(gè)構(gòu)造函數(shù),確實(shí)沒(méi)什么東西
          // 不行你可以直接看注釋3的代碼處
          sizeDeterminer = new SizeDeterminer(view); // 3 -->
          }
          // 非常簡(jiǎn)單的就只是對(duì)view進(jìn)行了一個(gè)賦值操作
          SizeDeterminer(@NonNull View view) {
          this.view = view;
          }

          f5a0df178bc9864ef2a735cdf8cf4591.webp那如果就只有上面那么一點(diǎn)不就完了??其實(shí)并不,如果你觀察了一下DrawableImageViewTargetBitmapImageViewTarget的其他方法,能發(fā)現(xiàn)這樣的一個(gè)特征。

          protected void setResource(Bitmap resource) {
          view.setImageBitmap(resource);
          }

          protected void setResource(@Nullable Drawable resource) {
          view.setImageDrawable(resource);
          }

          沒(méi)錯(cuò)!! 賦值操作,這個(gè)操作說(shuō)明最后其實(shí)的結(jié)束點(diǎn)肯定是在這里的,而調(diào)用他的函數(shù)最后也就是onResourceReady()這個(gè)方法,也就意味著圖片獲取成功了,不過(guò)呢這個(gè)請(qǐng)求完成肯定是和數(shù)據(jù)的獲取相互關(guān)聯(lián)的,也就是下面部分的內(nèi)容了。

          requestManager.track(target, request)

          // 以同步的方式完成數(shù)據(jù)的請(qǐng)求
          synchronized void track(@NonNull Target target, @NonNull Request request) {
          targetTracker.track(target); // 對(duì)當(dāng)前的目標(biāo)的生命周期有一個(gè)追蹤
          requestTracker.runRequest(request); // 2 --> 執(zhí)行操作正式開(kāi)啟
          }
          // 2 -->
          public void runRequest(@NonNull Request request) {
          requests.add(request);
          // 會(huì)對(duì)當(dāng)前的所有請(qǐng)求做一個(gè)判斷處理
          // 會(huì)根據(jù)當(dāng)前的狀態(tài)確定是否要進(jìn)行數(shù)據(jù)加載的操作
          // 一般來(lái)說(shuō)對(duì)應(yīng)的就是生命周期
          if (!isPaused) {
          request.begin();
          } else {
          request.clear();
          pendingRequests.add(request);
          }
          }

          那上面一段代碼說(shuō)明我們正常運(yùn)行的時(shí)候,網(wǎng)絡(luò)傳輸?shù)牟僮骺隙ㄊ且呀?jīng)在正常運(yùn)行了的,而其實(shí)正常沒(méi)有設(shè)置時(shí)調(diào)用的會(huì)是SingleRequest的類(lèi),不多逼逼,瞅瞅它的begin()方法有什么特殊之處了。

          public void begin() {
          synchronized (requestLock) {
          // 。。。。。

          // 如果正在運(yùn)行就拋出異常
          if (status == Status.RUNNING) {
          throw new IllegalArgumentException("Cannot restart a running request");
          }

          // 從緩存中直接拿出數(shù)據(jù)
          if (status == Status.COMPLETE) {
          onResourceReady(resource, DataSource.MEMORY_CACHE);
          return;
          }
          // ==============重中之重==============
          // 因?yàn)樵谏鲜鑫恼轮兄v到過(guò)了圖片的大小問(wèn)題
          // 在Glide中這里就是給出解決方案的地方,兩種方案:
          // 1. 給出了固定長(zhǎng)寬
          // 2. 沒(méi)有設(shè)置時(shí)
          status = Status.WAITING_FOR_SIZE;
          if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
          onSizeReady(overrideWidth, overrideHeight);
          } else {
          target.getSize(this);
          }
          // 使用一個(gè)占位符先頂替
          if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
          && canNotifyStatusChanged()) {
          target.onLoadStarted(getPlaceholderDrawable());
          }
          }
          }

          那接下來(lái)要講述的內(nèi)容就應(yīng)該是他的一些大小設(shè)置問(wèn)題了,Glide到底是用什么樣的方式完成大小的設(shè)置的呢?

          onSizeReady(overrideWidth, overrideHeight)

          public void onSizeReady(int width, int height) {
          stateVerifier.throwIfRecycled();
          synchronized (requestLock) {
          // .....
          status = Status.RUNNING;
          // 對(duì)長(zhǎng)寬重新進(jìn)行預(yù)估
          float sizeMultiplier = requestOptions.getSizeMultiplier();
          this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
          this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

          loadStatus =
          engine.load(各種參數(shù));
          // .....
          }
          }

          通過(guò)觀察對(duì)onSizeReady()函數(shù)發(fā)現(xiàn),他使用的方案其實(shí)又是一個(gè)名叫做engine.load()的方式。

          public  LoadStatus load(各種參數(shù)) {

          EngineResource memoryResource;
          synchronized (this) {
          memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);

          if (memoryResource == null) {
          return waitForExistingOrStartNewJob(各種參數(shù));
          }
          }
          cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
          return null;
          }

          上述是我省略過(guò)后的代碼,他表達(dá)意思其實(shí)非常之簡(jiǎn)單:

          (1)內(nèi)存里有數(shù)據(jù),你就從我內(nèi)存里拿。

          (2)內(nèi)存里沒(méi)數(shù)據(jù),那你就自己創(chuàng)建一個(gè)。

          這樣想來(lái),問(wèn)題又要往下繼續(xù)延伸了,正常來(lái)說(shuō)我們沒(méi)有數(shù)據(jù)啊,那就要去調(diào)用這個(gè)waitForExistingOrStartNewJob()方法,來(lái)完成圖片數(shù)據(jù)的獲取了。

          private  LoadStatus waitForExistingOrStartNewJob(各種參數(shù)) {
          EngineJob current = jobs.get(key, onlyRetrieveFromCache);
          if (current != null) {
          current.addCallback(cb, callbackExecutor);
          return new LoadStatus(cb, current);
          }

          EngineJob engineJob =
          engineJobFactory.build(各種參數(shù));

          DecodeJob decodeJob =
          decodeJobFactory.build(各種參數(shù));

          jobs.put(key, engineJob); // 對(duì)當(dāng)前驅(qū)動(dòng)工作進(jìn)行緩存操作

          engineJob.addCallback(cb, callbackExecutor);
          engineJob.start(decodeJob); // 開(kāi)啟圖片獲取工作

          return new LoadStatus(cb, engineJob);
          }

          能夠注意到有出現(xiàn)兩個(gè)新的類(lèi)EngineJobDecodeJob,轉(zhuǎn)換成中文去理解就是工作驅(qū)動(dòng)器和解碼工作,并且EngineJob內(nèi)部與線程池搭噶,最后肯定用于完成最后的圖片獲取工作,而DecodeJob作為被運(yùn)行的工作,處理邏輯就應(yīng)該在其之中。

          public void run() {
          DataFetcher localFetcher = currentFetcher;
          try {
          // .....
          runWrapped(); // 1 -->
          } catch (Exception e) {
          // .....
          } finally {
          // .....
          }
          }
          // 1 -->
          private void runWrapped() {
          switch (runReason) {
          case INITIALIZE:
          // 獲取 Stage.INITIALIZE 的下一步操作,也就是選擇三種方案
          // 1. 資源緩存:ResourceCacheGenerator
          // 2. 數(shù)據(jù)緩存:DataCacheGenerator
          // 3. 網(wǎng)絡(luò)資源:SourceGenerator
          stage = getNextStage(Stage.INITIALIZE);
          currentGenerator = getNextGenerator();
          runGenerators();
          break;
          case SWITCH_TO_SOURCE_SERVICE:
          runGenerators();
          break;
          case DECODE_DATA:
          decodeFromRetrievedData();
          break;
          default:
          throw new IllegalStateException("Unrecognized run reason: " + runReason);
          }
          }

          其實(shí)上述內(nèi)容中已經(jīng)開(kāi)始講述到我們常見(jiàn)的三大緩存了,也就是網(wǎng)絡(luò)緩存、磁盤(pán)緩存和內(nèi)存緩存,這段代碼中其實(shí)已經(jīng)開(kāi)始涉及網(wǎng)絡(luò)緩存和磁盤(pán)緩存了。

          SourceGenerator:關(guān)于網(wǎng)絡(luò)緩存

          private void runGenerators() {
          currentThread = Thread.currentThread();
          startFetchTime = LogTime.getLogTime();
          boolean isStarted = false;
          while (!isCancelled
          && currentGenerator != null
          && !(isStarted = currentGenerator.startNext())) { // 1 -->
          stage = getNextStage(stage);
          currentGenerator = getNextGenerator();
          // 只對(duì)Source這個(gè)枚舉類(lèi)型相應(yīng)
          if (stage == Stage.SOURCE) {
          reschedule();
          return;
          }
          }
          // 已完成就通知失敗
          if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
          notifyFailed();
          }
          }
          // 1-->
          public boolean startNext() {
          // 需要數(shù)據(jù)有緩存才行
          if (dataToCache != null) {
          Object data = dataToCache;
          dataToCache = null;
          cacheData(data);
          }

          if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
          return true;
          }
          sourceCacheGenerator = null;

          loadData = null;
          boolean started = false;
          while (!started && hasNextModelLoader()) {
          // 從映射表找出能夠?qū)?yīng)上的圖片類(lèi)型的ModelLoader
          loadData = helper.getLoadData().get(loadDataListIndex++);
          if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
          started = true;
          // 完成數(shù)據(jù)的加載
          startNextLoad(loadData);
          }
          }
          return started;
          }

          針對(duì)注釋1進(jìn)行探討,這里的話,我們就盡量不放代碼查看了,因?yàn)榭戳诉@么多代碼,你肯定也累了。其實(shí)你能夠猜測(cè)到它的下一步是網(wǎng)絡(luò)請(qǐng)求,那如果獲取成功了,是要直接進(jìn)行圖片數(shù)據(jù)的顯示嗎?那三次緩存應(yīng)該在什么時(shí)機(jī)進(jìn)行操作呢?因?yàn)榇a量的原因,這里我們用圖來(lái)展示流程。

          66e9568ae81f7e8b494f9652a229f514.webp

          從圖中可以知道,其實(shí)從網(wǎng)絡(luò)獲取的資源最后還是要被放到磁盤(pán)中進(jìn)行緩存的,而磁盤(pán)緩存成功之后,接下來(lái)要干的事情就是要去通知View把獲取的數(shù)據(jù)進(jìn)行解碼。這里你是否有一定的疑問(wèn)了?

          你沒(méi)有聽(tīng)錯(cuò),就是解碼,如果你去各個(gè)官方查看圖片的時(shí)候,很多給的都是后期重新被編碼過(guò)的數(shù)據(jù),本身數(shù)據(jù)其實(shí)并不能夠在直接運(yùn)行的,而解碼就是讓圖片正式可視化的必經(jīng)之路,也就是DecodeJob的本質(zhì)工作了,對(duì)應(yīng)的函數(shù)就是decodeFromRetrievedData()方法,把磁盤(pán)中拷貝出來(lái)的數(shù)據(jù)要進(jìn)行解碼操作。

          private void decodeFromRetrievedData() {
          Resource resource = null;
          // 將網(wǎng)絡(luò)獲取的數(shù)據(jù)進(jìn)行解碼操作
          try {
          resource = decodeFromData(currentFetcher, currentData, currentDataSource); // 1 -->
          } catch (GlideException e) {
          }
          // 解碼完成,發(fā)出通知
          if (resource != null) {
          notifyEncodeAndRelease(resource, currentDataSource); // 2-->
          } else {
          runGenerators();
          }
          }

          你能夠發(fā)現(xiàn)我在這段代碼中打了兩個(gè)注釋?zhuān)鋵?shí)對(duì)應(yīng)的就是兩大操作解碼完成,通知可以顯示了。

          decodeFromData(currentFetcher, currentData, currentDataSource);

          下面會(huì)給出一段很長(zhǎng)的深度調(diào)用代碼。

          1)resource = decodeFromData(currentFetcher, currentData, currentDataSource);
          2)Resource result = decodeFromFetcher(data, dataSource);
          3return path.load(
          rewinder, options, width, height, new DecodeCallback(dataSource));
          4return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
          5)result = path.decode(rewinder, width, height, options, decodeCallback);
          6
          public Resource decode(
          DataRewinder rewinder,
          int width,
          int height,
          @NonNull Options options,
          DecodeCallback callback)

          throws GlideException
          {
          // 這里會(huì)有很多轉(zhuǎn)化的方法,一般來(lái)說(shuō)對(duì)圖片最常見(jiàn)的就是轉(zhuǎn)成Bitmap
          Resource decoded = decodeResource(rewinder, width, height, options);
          Resource transformed = callback.onResourceDecoded(decoded);
          return transcoder.transcode(transformed, options);
          }

          decode()這個(gè)函數(shù)其實(shí)做了三件事:

          1. decodeResource 將原始數(shù)據(jù)轉(zhuǎn)換成我們?cè)紙D片的過(guò)程;
          2. callback.onResourceDecoded()是當(dāng)?shù)玫搅嗽紙D片之后對(duì)圖片繼續(xù)處理過(guò)程;
          3. transcoder.transcode()會(huì)使用BitmapDrawableTranscoder進(jìn)行再包裝

          decodeResource中可以轉(zhuǎn)化的部分解碼器9a42cc6c44fac4e29e9b548d68283924.webp

          那這個(gè)時(shí)候你就正式拿到了一張圖片了,那下一步還需要干嘛???顯示?。。?!廢了這么大周折,還不趕緊拿去顯示,不是做了一大堆無(wú)用功嘛?

          notifyEncodeAndRelease(resource, currentDataSource);

          只看少量代碼來(lái)完成這項(xiàng)工作

          1)notifyComplete(result, dataSource);
          2
          private void notifyComplete(Resource resource, DataSource dataSource) {
          setNotifiedOrThrow();
          callback.onResourceReady(resource, dataSource);
          }

          你是否有注意到這樣的問(wèn)題,onResourceReady()是不是有點(diǎn)眼熟,在很上面的glideContext.buildImageViewTarget(view, transcodeClass),也就是構(gòu)建放置的目標(biāo)中我們就已經(jīng)講到過(guò)這個(gè)方法了,最后會(huì)通過(guò)一個(gè)set()的方法來(lái)將數(shù)據(jù)進(jìn)行放置。

          那基本上來(lái)說(shuō),上面就是一個(gè)比較詳細(xì)的Glide的源碼分析,因?yàn)榇a是在太多了,所以我這里刪去了很多。

          一些思考

          其實(shí)你會(huì)發(fā)現(xiàn)我并沒(méi)有正式講完三級(jí)緩存,還差一個(gè)內(nèi)存緩存沒(méi)講不是?

          其實(shí)這是一個(gè)很早就被用到的方法,他對(duì)應(yīng)的位置就在SingleRequest被調(diào)用了OnSizeReady()方法的時(shí)候有個(gè)engine.load(),里面就包含了第三級(jí)緩存內(nèi)存緩存,里面對(duì)應(yīng)的是這樣的一段代碼memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);以及他深度調(diào)用后的EngineResource active = loadFromActiveResources(key);從活躍的的資源數(shù)據(jù)中進(jìn)行尋找。同樣是一個(gè)非常簡(jiǎn)單的實(shí)現(xiàn)手法。

          final Map activeEngineResources = new HashMap<>();

          就是通過(guò)一個(gè)Map對(duì)數(shù)據(jù)進(jìn)行了保存,這樣從復(fù)用的角度上來(lái)看就被比較好的繼承了。

          但如果不是活躍資源數(shù)據(jù)呢?

          不要著急,還有一些數(shù)據(jù)還會(huì)在cache的變量中被保存著,這個(gè)方法里就是用了我們經(jīng)常會(huì)提及到的LRUCache的一個(gè)淘汰算法,這里的詳細(xì)請(qǐng)查看我的另外一篇文章:Glide都在用的LruCache,你學(xué)會(huì)了嗎?。


          瀏覽 157
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    最新国产三级在线 | 美女视频黄a视频全免费不卡 | 久久秘 一区二区三区四区 | 青青视频欧美 | 婷婷丁香社区五月天 |