Android框架源碼分析——Glide源碼分析

1、Glide的使用

    Glide.with(this).load(url).into(imageView)

在當下Glide已經是很常見的圖片加載工具了,相信很多開發者都體會到其方便指出,Glide的使用就簡單一句話即可完成圖片的加載,但不要小看這句話,Glide的背後可是作出了成噸的工作,今天整理一下Glide的相關筆記,跟隨上面的一句代碼探索Glide的奇妙指出;

2、with()

   public static RequestManager with(@NonNull FragmentActivity activity) {
      return getRetriever(activity).get(activity);
    }
  • getRetriever(activity):獲取RequestManagerRetriever
       private static RequestManagerRetriever getRetriever(@Nullable Context context) {
          return Glide.get(context).getRequestManagerRetriever(); 
        }

從上面的代碼看出with()中直接調用一行代碼,這行代碼執行了getRetriever()和get()兩個方法,getRetriever()中獲取Glide的實例,然後獲取Glide配置中的RequestManagerRetriever對象,下面先看看Glide的初始化

2.1、Glide初始化
   private static void initializeGlide(@NonNull Context context) {
      initializeGlide(context, new GlideBuilder());
    }
    @SuppressWarnings("deprecation")
    private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
      //(1)獲取@GlideModules註解生成的類
      GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
       //(2)調用擴展GlideModule中的設置方法,加載初始化的配置,這裏可以在項目中自定義Glide的配置
      annotationGeneratedModule.applyOptions(applicationContext, builder); 
      Glide glide = builder.build(applicationContext); //(3)執行build()實例化Glide
      Glide.glide = glide; //(4)賦值單例提供的Glide
    }

簡述上面的流程:

  1. 創建GlideBuilder實例,然後反射獲取程序中擴展的@GlideModule生成類,調用applyOptions()加載用戶自定義的配置,這裏的針對Glide的Generated API使用時的配置,關於Generated API的使用自行查閱文檔
  2. 使用GlideBuilder實例化Glide,並單例對外提供
2.2、GlideBuilder——配置並實例化Glide
Glide build(@NonNull Context context) {
  if (sourceExecutor == null) {
    sourceExecutor = GlideExecutor.newSourceExecutor(); //(1)實例化執行網絡資源加載線程池
  }
  if (diskCacheExecutor == null) {
    diskCacheExecutor = GlideExecutor.newDiskCacheExecutor(); //(2)實例化執行磁盤緩存的線程池
  }
  if (animationExecutor == null) {
    animationExecutor = GlideExecutor.newAnimationExecutor(); //(3)實例化動畫線程池
  }
  if (memorySizeCalculator == null) {
    memorySizeCalculator = new MemorySizeCalculator.Builder(context).build(); //(4)實例化計算內存緩存大小
  }
  if (connectivityMonitorFactory == null) {
    connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); //(5)
  }
  if (bitmapPool == null) {
    int size = memorySizeCalculator.getBitmapPoolSize();
    if (size > 0) {
      bitmapPool = new LruBitmapPool(size); //(6)初始化Bitmap池
    } else {
      bitmapPool = new BitmapPoolAdapter();
    }
  }
  if (arrayPool == null) {
    arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes()); //(7)
  }
  if (memoryCache == null) {
    memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());//(8)初始化內存緩存
  }
  if (diskCacheFactory == null) {
    diskCacheFactory = new InternalCacheDiskCacheFactory(context); //(9)實例化磁盤緩存工廠
  }
  if (engine == null) { //(10)將設置的信息初始化Engine
    engine = new Engine(
            memoryCache,
            diskCacheFactory,
            diskCacheExecutor,
            sourceExecutor,
            GlideExecutor.newUnlimitedSourceExecutor(),
            animationExecutor,
            isActiveResourceRetentionAllowed);
  }
   defaultRequestListeners = Collections.emptyList(); //(11)請求監聽器
  
  RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory);12return new Glide( //(13)創建Glide
      context,
      engine,
      memoryCache,
      bitmapPool,
      arrayPool,
      requestManagerRetriever,
      connectivityMonitorFactory,
      logLevel,
      defaultRequestOptions.lock(),
      defaultTransitionOptions,
      defaultRequestListeners,
      isLoggingRequestOriginsEnabled);
}

GlideBuilder初始化Gild時,完成了各種線程池和緩存的創建和配置,具體見代碼中的註釋這裏很多的配置對後面的分析很重要,最後創建的RequestManagerRetriever就是上面獲取的實例

  • RequestManagerRetriever.get():根據傳入的Context不同分別調用不同的重載方法創建RequestManager
public RequestManager get(@NonNull Fragment fragment) {//get()多個重載方法
  if (Util.isOnBackgroundThread()) { //(1)在後臺線程執行時,綁定Application生命週期
    return get(activity.getApplicationContext()); 
  } else {
    FragmentManager fm = activity.getSupportFragmentManager(); //
    return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
  }
}
public RequestManager get(@NonNull Activity activity) { //get()對Activity的重載
if (Util.isOnBackgroundThread()) {
。。。。。。
return fragmentGet( activity, fm,null, isActivityVisible(activity));
}
}
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {  //get()對Fragment的重載
  if (Util.isOnBackgroundThread()) { 
。。。。。。
    return supportFragmentGet(  activity, fm,null, isActivityVisible(activity));
  }
}
public RequestManager get(@NonNull Context context) { //get()對Context的重載,判斷類型執行對應的重載方法
 if (context == null) {
  throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
  if (context instanceof FragmentActivity) {
    return get((FragmentActivity) context);
  } else if (context instanceof Activity) {
    return get((Activity) context);
  } else if (context instanceof ContextWrapper) {
    return get(((ContextWrapper) context).getBaseContext());
  }
}
  return getApplicationManager(context); //對於傳入Application Context的調用getApplicationManager()綁定Application週期
}
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
  if (applicationManager == null) {
    synchronized (this) {
      if (applicationManager == null) {
        Glide glide = Glide.get(context.getApplicationContext());
        applicationManager =
            factory.build(
                glide,
                new ApplicationLifecycle(),
                new EmptyRequestManagerTreeNode(),
                context.getApplicationContext());
      }
    }
  }
  return applicationManager;
}
//對於非Application,根據傳入的Activity/Fragment的包(app或v4)分別調用fragmentGet或supportFragmentGet,最終目的都在Activity/Fragment中添加隱藏的Fragment
@NonNull
private RequestManager supportFragmentGet(
    @NonNull Context context,
    @NonNull FragmentManager fm,
    @Nullable Fragment parentHint,
    boolean isParentVisible) {
  //(1)從傳入的fm中獲取添加的Fragment,如果爲null則創建並使用fm添加一個隱藏的Fragment,用於監聽生命週期的變化
  SupportRequestManagerFragment current =     
      getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
  RequestManager requestManager = current.getRequestManager();
  if (requestManager == null) {
    Glide glide = Glide.get(context); 
 //(2)調用factory創建RequestManager,傳入ActivityFragmentLifecycle()監聽Fragment的生命週期,然後綁定RequestManager和Fragment
    requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
    current.setRequestManager(requestManager); 
  }
  return requestManager;
}

總結:

  1. get()方法中主要是根據請求傳入的Context類型,執行不同邏輯用於確定請求的生命週期,這裏採用常見的添加隱形Fragment的方式監聽生命週期
  2. 傳入Application類型的Context調用get()綁定Application生命週期
  3. 傳入Activity/Fragment類型Context,若在非UI線程,則綁定Application週期,在UI線程爲Activity/Fragment添加隱形Fragment監聽生命週期
  4. 綁定生命週期實例化Glide後,調用factory創建RequestManager實例,這裏默認使用RequestManagerFactory
  5. RequestManagerFactory:Glide的默認工廠,實例化RequestManager保存請求的生命週期lifecycle,關於lifecycle如何控制生命週期在後面將會介紹;
requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
//(1)factory默認的是RequestManagerFactory
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);//(2)創建RequestManager
  }
};

3、load()

public RequestBuilder<Drawable> load(@Nullable String string) {
  return asDrawable().load(string); 
}
public RequestBuilder<Drawable> asDrawable() {
  return as(Drawable.class); 
}
public <ResourceType> RequestBuilder<ResourceType> as( @NonNull Class<ResourceType> resourceClass) {
  return new RequestBuilder<>(glide, this, resourceClass, context); //創建RequestBuilder
}
  • RequestBuilder.load():保存請求的數據(圖片地址)
public RequestBuilder<TranscodeType> load(@Nullable String string) {
  return loadGeneric(string);
}
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
  this.model = model; //保存請求的url
  return this;
}

在with()中知道程序最終創建了RequestManager對象,RequestManager.load()方法中根據傳參類型創建對應的RequestBuilder並設置加載最終返回的數據類型,然後調用RequestBuilder.load(),此處傳入的數據類型將影響最終加載圖片的類型,因爲在加載完成後會根據此處設置的resourceClass進行響應的轉換;

4、into():加載圖片顯示到視圖中

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
switch (view.getScaleType()) { // (1)根據ImageView的scaleType設置RequestOptions
  case CENTER_CROP:
    requestOptions = requestOptions.clone().optionalCenterCrop();
    break;
  case CENTER_INSIDE:
    requestOptions = requestOptions.clone().optionalCenterInside();
    break;
  case FIT_CENTER:
  case FIT_START:
  case FIT_END:
    requestOptions = requestOptions.clone().optionalFitCenter();
    break;
  case FIT_XY:
    requestOptions = requestOptions.clone().optionalCenterInside();
    break;
}
  return into( // (2)執行into()
      glideContext.buildImageViewTarget(view, transcodeClass),
      null,
      requestOptions,
      Executors.mainThreadExecutor());
}

into()方法中代碼邏很簡潔:

  • 根據設置ImageView條件配置響應的Options;

  • 根據要加載的圖片類型,創建對應Target,此處的Target保存真正的ImageView並負責最終的圖片顯示

  • 設置請求後的顯示線程爲主線程

  • 調用into()執行圖片加載

  • GlideContext.buildImageViewTarget():根據請求的數據類型,調用ImageViewTargetFactory創建對應的Target,創建的Target封裝試圖View,這裏以請求的Drawable爲例,此處創建的是DrawableImageViewTarget

@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
    @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
  return imageViewTargetFactory.buildTarget(imageView, transcodeClass);   //此處的transcodeClass由上面知道傳遞的是Drawable.class
}
public class ImageViewTargetFactory {
  @NonNull
  @SuppressWarnings("unchecked")
  public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
      @NonNull Class<Z> clazz) {
    if (Bitmap.class.equals(clazz)) {
      return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); //創建DrawableImageViewTarget
    } else { 
  }
}
  • into():構建最終的請求Request並執行請求
private <Y extends Target<TranscodeType>> Y into(
    @NonNull Y target,
    @Nullable RequestListener<TranscodeType> targetListener,
    BaseRequestOptions<?> options,
    Executor callbackExecutor) {
  Request request = buildRequest(target, targetListener, options, callbackExecutor); //(1)構建Request
  target.setRequest(request); //(2)調用ViewTarget保存Request
  requestManager.track(target, request); //(3)執行Request請求
  return target;
}

上面的代碼就做了兩件事,但這兩件事完成了整個的數據請求:

  1. 創建Request,此處最終創建的是SingleRequest
  2. 執行Request加載
4.1、創建SingleRequest實例
public static <R> SingleRequest<R> obtain(……){
  SingleRequest<R> request = (SingleRequest<R>) POOL.acquire();  //(1)獲取或創建Request
  if (request == null) {
      request = new SingleRequest<>(); //創建Request
  }
  request.init( //調用Request.init()初始化請求信息和圖片加載信息
    context, 
    glideContext,
    model,  //請求的地址
    transcodeClass, //請求參數類型,此處爲String
    requestOptions, //設置的options
    overrideWidth, //設置的寬、高參數
    overrideHeight,
    priority,
    target,  //設置顯示的Target
    targetListener,  //設置監聽Target的加載
    requestListeners,   //設置請求監聽
    requestCoordinator,
    engine, 
    animationFactory, //加載動畫
    callbackExecutor); //設置執行的線程池
 }
4.2、執行Request,開始加載數據
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
  requestTracker.runRequest(request); //執行請求的Target
}
  • RequestTracker.runRequest():方法最終調用SingleRequest的方法
public void runRequest(@NonNull Request request) {
  requests.add(request);   //保存請求的Request
  if (!isPaused) { //判斷Glide是否暫停
    request.begin(); //直接進行請求
  } else {
    request.clear();
    pendingRequests.add(request); //暫停時保存任務
  }
}

runRequest中首先保存要執行的請求,然後判斷Glide的加載是否停止,初步猜測這裏的停止應該和生命週期有關,如果停止將請求Request加入到人去列表中,否則直接調用begin()執行Request

  • SingleRequest.begin()
@Override
public synchronized void begin() {
  status = Status.WAITING_FOR_SIZE; //設置標識位爲測量尺寸
  if (Util.isValidDimensions(overrideWidth, overrideHeight)) {  //如果已設置寬高尺寸,則直接調用 onSizeReady(),否則測量尺寸後再調用
    onSizeReady(overrideWidth, overrideHeight);
  } else {
    target.getSize(this); //測量後調用
  }
  if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
      && canNotifyStatusChanged()) {
    target.onLoadStarted(getPlaceholderDrawable()); //回調請求開始,顯示佔位Drawable
  }
}

begin()方法執行3個過程:

  1. 如果已設置寬高尺寸,則直接調用 onSizeReady()
  2. 如果未設置則調用ImageView的測量方法,測量結束後回調onSizeReady()
  3. 回調target.onLoadStarted(getPlaceholderDrawable())表示加載開始顯示佔位圖
  • SingleRequest.onSizeReady():繼續請求加載
public synchronized void onSizeReady(int width, int height) {
  status = Status.RUNNING;
  loadStatus = engine.load( 
          glideContext,
          model, //請求參數
          requestOptions.getSignature(), //請求的requestOptions
          this.width, //請求寬、高
          this.height,
          requestOptions.getResourceClass(),
          transcodeClass, //請求參數類型
          priority,
          requestOptions.getDiskCacheStrategy(), //請求設置的RequestOptions
          requestOptions.getTransformations(),
          requestOptions.isTransformationRequired(),
          requestOptions.isScaleOnlyOrNoTransform(),
          requestOptions.getOptions(),
          requestOptions.isMemoryCacheable(),
          requestOptions.getUseUnlimitedSourceGeneratorsPool(),
          requestOptions.getUseAnimationPool(),
          requestOptions.getOnlyRetrieveFromCache(),
          this, // 此處傳遞的是ResourceCallback,SingleRequest實現了ResourceCallback接口
          callbackExecutor); //執行線程池
}

onSizeReady中標記運行狀態,調用Engine.load()加載數據,傳入的參數也都是加載圖片基本配置和條件;

  • Engine.load():執行加載數據
public synchronized <R> LoadStatus load() {
  EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, //(1)創建緩存的Key
      resourceClass, transcodeClass, options);
  EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); //(2)從活躍的引用中加載緩存信息
  
  EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); //(3)從緩存中獲取緩存實例
  EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); //從緩存的Jobs列表中獲取EngineJob
  if (current != null) {
    current.addCallback(cb, callbackExecutor);
    return new LoadStatus(cb, current);
  }
  EngineJob<R> engineJob =  engineJobFactory.build( //對於新執行的任務,創建EngineJob
          key,
          isMemoryCacheable,
          useUnlimitedSourceExecutorPool,
          useAnimationPool,
          onlyRetrieveFromCache);
  DecodeJob<R> decodeJob =  decodeJobFactory.build( //創建執行解析任務的DecodeJob
          glideContext,
          model,
          key,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          onlyRetrieveFromCache,
          options,
          engineJob); //在DecodeJob中添加DecodeJob.Callback實例,處理數據回調
  jobs.put(key, engineJob); //保存執行的任務信息
  engineJob.addCallback(cb, callbackExecutor); //將傳入的SingleRequest和執行的線程池對應添加到列表中
  engineJob.start(decodeJob);  //啓動執行任務
  return new LoadStatus(cb, engineJob);
}

load()中執行的邏輯就明顯體現了Glide的緩存原理,詳細的執行會在緩存中介紹,這裏製作流程介紹,簡單總結:

  1. 首先根據加載的條件創建Glide 的緩存Key;
  2. 根據Key先從活躍的資源中獲取,獲取成功則返回,否則向下執行;
  3. 再從內存緩存中獲取,獲取成功則返回,否則向下執行;
  4. 對於都未獲取到的則創建DecodeJob和EngineJob加載並解析資源;
  • EngineJob.start():獲取執行任務的線程池並執行任務
public synchronized void start(DecodeJob<R> decodeJob) {
  this.decodeJob = decodeJob;
  GlideExecutor executor = decodeJob.willDecodeFromCache()  //獲取執行的線程池
      ? diskCacheExecutor
      : getActiveSourceExecutor();
  executor.execute(decodeJob); //使用線程池執行任務,程序回到DecodeJob.run()
}
  • DecodeJob.run():線程池執行加載的方法
@Override
public void run() {
    runWrapped();
}
private void runWrapped() {
  switch (runReason) {
    case INITIALIZE:
      stage = getNextStage(Stage.INITIALIZE);  //根據緩存情況獲取下一步的執行條件
      currentGenerator = getNextGenerator();  //獲取具體執行的DataFetcherGenerator實例
      runGenerators(); //執行Generators
      break;
    case SWITCH_TO_SOURCE_SERVICE:
      runGenerators();
      break;
    case DECODE_DATA:
      decodeFromRetrievedData();
      break;
  }
}

private Stage getNextStage(Stage current) {
  switch (current) {
    case INITIALIZE:
      return diskCacheStrategy.decodeCachedResource()  //(1)判斷存在轉換後緩存文件則返回Stage標識,否則遞歸繼續判斷
          ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
    case RESOURCE_CACHE:
      return diskCacheStrategy.decodeCachedData() //(2)判斷存在源數據緩存存在,則設置Stage標識,否則遞歸繼續判斷
          ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
    case DATA_CACHE: //(3)解析後文件和源文件緩存都不存在的情況:
      return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE; //如果設置只讀緩存則請求結束,否則獲取資源
  }
}
//根據上一步設置的要執行的Stage的標識,獲取執行的DataFetcherGenerator實例
private DataFetcherGenerator getNextGenerator() {
  switch (stage) {
    case RESOURCE_CACHE:
      return new ResourceCacheGenerator(decodeHelper, this);  //(1)從轉換資源緩存中獲取
    case DATA_CACHE:
      return new DataCacheGenerator(decodeHelper, this);  //(2)從緩存的源文件中獲取
    case SOURCE:
      return new SourceGenerator(decodeHelper, this); //(3)沒有緩存資源,執行加載
  }
}
//Glide巧妙的設置一次執行:獲取處理緩存資源 -> 獲取原始緩存資源 -> 網絡加載;只要一個環節加載成功,返回true則跳出循環
private void runGenerators() {
  boolean isStarted = false;
  while (!isCancelled && currentGenerator != null
      && !(isStarted = currentGenerator.startNext())) { //調用startNext()執行加載,成功返回true,跳出循環
    stage = getNextStage(stage);
    currentGenerator = getNextGenerator();
  }
}

關於上面的代碼還是需要仔細思考下的,Glide使用getNextStage()和getNextGenerator()方法巧妙的實現了多種判斷,總結上面方法執行邏輯如下:

  1. getNextStage():根據當前狀態獲取下一步的操作類型,開始爲INITIALIZE狀態,此時判斷是否有轉換後的緩存,有則設置爲RESOURCE_CACHE,否則繼續回調判斷;此時傳入爲RESOURCE_CACHE狀態,判斷是否有原數據緩存,有設置DATA_CACHE,否則遞歸判斷,傳參爲DATA_CACHE;此時判斷是否設置制度緩存,如果設置但沒有緩存加載結束,未設置則設置SOURCE標識,表示要去加載資源;
  2. getNextGenerator():根據上一步設置的標識,創建對應的任務實例(讀取轉換後文件、源緩存文件、獲取網絡資源)
  3. runGenerators():執行任務,在執行結束後並設置標識
4.3、SourceGenerator
SourceGenerator(DecodeHelper<?> helper, FetcherReadyCallback cb) {
  this.helper = helper;
  this.cb = cb; //保存傳入的FetcherReadyCallback實例
}
@Override
public boolean startNext() {
  while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);  // loadData是在Glide初始化時註冊的
      loadData.fetcher.loadData(helper.getPriority(), this); //獲取Fetcher,真正執行網絡請求的點地方,
    }
  }
  return started;
}

方法執行runGenerators()會調用SourceGenerator.statNext()方法,statNext首先使用helper獲取loadData,此處的 helper是DecodeHelper實例,創建SourceGenerator時傳入的參數,方法回到DecodeJob中,在DecodeJobFactory創建DecodeJob時掉調用了DecodeJob.init(),init()方法中decodeHelper.init初始化decodeHelper

private final DecodeHelper<R> decodeHelper = new DecodeHelper<>();
DecodeJob<R> init(
   ……….) {
  decodeHelper.init(
      glideContext,  
      diskCacheProvider); 
}

helper.getLoadData()獲取ModelLoader.LoadData()對象,Glide初始化時調用.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())註冊的HttpGlideUrlLoader.Factory(),最終創建new LoadData<>(url, new HttpUrlFetcher(url, timeout)),後面加載的loadData.fetcher 其實調用的就是HttpUrlFetcher實例;

  • HttpUrlFetcher :最終執行網絡請求,使用HttpUrlConnection執行圖片加載
@Override
public void loadData(@NonNull Priority priority,@NonNull DataCallback<? super InputStream> callback) {
    InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
}
//使用HttpUrl執行網絡請求
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
    Map<String, String> headers) throws IOException {
  urlConnection = connectionFactory.build(url); //使用HttpUrlConnection執行網絡請求
  for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
    urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
  }
  urlConnection.setConnectTimeout(timeout);
  urlConnection.setReadTimeout(timeout);
  urlConnection.setUseCaches(false);
  urlConnection.setDoInput(true);
  urlConnection.setInstanceFollowRedirects(false);
  urlConnection.connect();
  stream = urlConnection.getInputStream();
  if (isCancelled) {
    return null;
  }

上面的邏輯很簡介直接請求網絡加載圖片,Glide的默認使用HttpUrl加載圖片,當然Glide也提供了配置Okhttp的方法;

5、請求成功回調

  • HttpUrlFetcher執行網絡請求成功後,請求後回調的Callback,此處Callback是傳入的SourceGenerator
 InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
    callback.onDataReady(result);   //執行請求成功回調
  } catch (IOException e) {
    callback.onLoadFailed(e);   //執行請求失敗回調
  } finally {
  }
  • SourceGenerator.onDataReady()
@Override
public void onDataReady(Object data) {
  DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
  if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) { //判斷是否緩存原始數據
    dataToCache = data;
    cb.reschedule();  // 緩存原始數據
  } else { //處理獲取的數據
    cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,  // 此處的cb創建時傳入的DecodeJob中創建的
        loadData.fetcher.getDataSource(), originalKey);
  }
}

如果Glide設置允許緩存源數據則執行數據緩存,否則執行DecodeJob.onDataFetcherReady進行轉換資源,此處cb其實是傳入的DecodeJob對象,所以方法回到進入DecodeJob;

  • DecodeJob.onDataFetcherReady():執行數據轉換和解析
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,DataSource dataSource, Key attemptedKey) {
      decodeFromRetrievedData();
}
private void decodeFromRetrievedData() {
  Resource<R> resource = null;
  try {  //(1)執行圖片的轉換
    resource = decodeFromData(currentFetcher, currentData, currentDataSource);
  } catch (GlideException e) {
  }
  if (resource != null) {
    notifyEncodeAndRelease(resource, currentDataSource); //(2) 通知加載結束並緩存數據
  } else {
    runGenerators();
  }
}
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
  Resource<R> result = resource;
  notifyComplete(result, dataSource); // notifyCOmplete()調用callback.onResourceReady(resource, dataSource);
  stage = Stage.ENCODE;
}

總結:

  1. 調用decodeFromData執行圖片的轉換
  2. 通知加載結束並緩存數據,此處回到callback爲EngineJob對象
  • EngineJob.onResourceReady():執行加載資源回調
class EngineJob<R> implements DecodeJob.Callback<R>{
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
  synchronized (this) {
    this.resource = resource;
    this.dataSource = dataSource;
  }
  notifyCallbacksOfResult();
}
@Synthetic
void notifyCallbacksOfResult() {
  synchronized (this) {
}
for (final ResourceCallbackAndExecutor entry : copy) {
  entry.executor.execute(new CallResourceReady(entry.cb));  //調用線程池執行CallResourceReady
}
}

對上面最後執行代碼中的entey其實是ResourceCallbacksAndExecutors()的實例,內部封裝了List用於保存ResourceCallbackAndExecutor,代碼中使用for循環遍歷copy中的集合,那是什麼時候添加的呢?這裏代碼回到Engine.load()中有一行代碼(見下面),此時將cb保存到ResourceCallbackAndExecutor中,然而此處的cb就是SingleRequest中調用load()傳入的this,即cb就是SingleRequest

engineJob.addCallback(cb, callbackExecutor);
  • CallResourceReady:對資源引用計數加一,回到將callCallbackOnResourceReady()將結果回傳給SingleRequest
 @Override
  public void run() {
        engineResource.acquire();  
        callCallbackOnResourceReady(cb);  //加載結束回調方法
  }
}
synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
  try {
    cb.onResourceReady(engineResource, dataSource); 
  } 
}
  • SingleRequest.onResourceReady()
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
  stateVerifier.throwIfRecycled();
  loadStatus = null;
  if (resource == null) {
    onLoadFailed(exception); //加載失敗回調
    return;
  }
  Object received = resource.get();
  if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
    onLoadFailed(exception);
    return;
  }
  onResourceReady((Resource<R>) resource, (R) received, dataSource);    //執行成功數據回調
}
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
  try {
    if (!anyListenerHandledUpdatingTarget) {
      target.onResourceReady(result, animation); //執行Target,此處就是前面創建的DrawableImageViewTarget
    }
  } finally {
    isCallingCallbacks = false;
  }
}

看到最初創建請求的地方代表離成功不遠了,SingleRequest中根據加載的結果,回調Target中的方法,由前面的分析知道此時的Target是DrawableImageViewTarget實例

  • DrawableImageViewTarget
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
  if (transition == null || !transition.transition(resource, this)) {
    setResourceInternal(resource); //不執行顯示動畫
  } else {
    maybeUpdateAnimatable(resource); //執行顯示動畫
  }
}
private void setResourceInternal(@Nullable Z resource) {
  setResource(resource); //調用抽象方法,此方法在DrawableImageViewTarget中實現
  maybeUpdateAnimatable(resource);
}
@Override
protected void setResource(@Nullable Drawable resource) {
  view.setImageDrawable(resource);  //最終的顯示結果
}
  1. ImageViewTarget.onResourceReady()中根據設置的transtion確定是否執行動畫並分別處理
  2. 調用重寫的抽象方法,爲保存的ImageView設置圖片

Glide的源碼分析到此結束了,由於筆記很早之前就做了但一直沒整理成博客,這次的整理又整體看了遍源碼,即是複習也是學習,希望對想要了解的同學有所幫助;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章