Glide源碼分析之Glide和RequestManager構建過程

Glide源碼分析之Glide和RequestManager構建過程 Glide源碼分析之自定義模塊及Glide如何觸發網絡請求(未發佈) Glide源碼分析之load(url)和into(iv)(未發佈) Glide源碼分析之緩存機制(未發佈)android

基本用法

多數狀況下,使用Glide加載圖片很是簡單,一行代碼足矣:數組

Glide.with(fragment).load(myUrl).into(imageView)
複製代碼

取消加載:緩存

Glide.with(fragment).clear(imageView);
複製代碼

實際上,Glide.with() 中傳入的 Activity 或 Fragment 實例銷燬時,Glide 會自動觀察 Activity 或 Fragment 的生命週期取消加載並回收資源,實際上Glide爲了監聽Activity 或 Fragment的聲明週期會在內部添加一個fragment就是爲監聽生命週期。網絡

看一下Glide.with()的源碼:app

/**
 * with方法主要的邏輯:
 * 一、在1步驟中經過getRetriever獲取到在初始化Glide時建立的RequestManagerRetriever實例;
 * 二、在2步驟中經過RequestManagerRetriever的get方法獲取RequestManager實例。
 *
 * <p>
 * RequestManagerRetriever用於建立新的RequestManagers或從activity和fragment中檢索現有的RequestManagers
 *
 * @param context
 * @return
 */
@NonNull
public static RequestManager with(@NonNull Context context) {
    // 調用getRetriever獲取RequestManagerRetriever
    RequestManagerRetriever requestManagerRetriever = getRetriever(context);// 1
    // 調用RequestManagerRetriever的get方法,獲取RequestManager(圖片請求加載管理者)
    RequestManager requestManager = requestManagerRetriever.get(context); // 2
    return requestManager;
}


/**
 * 請求資源使用Activityh生命週期同步
 *
 * @param activity
 * @return
 */
@NonNull
public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
}

/**
 * 請求資源使用FragmentActivity生命週期同步
 */
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
}

/**
 * 請求資源使用Fragment生命週期同步
 */
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
}

/**
 * 請求資源使用android.app.Fragment生命週期同步
 */
@SuppressWarnings("deprecation")
@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
}

/**
 * 經過View去搜索其依附的Activity或者Fragment並使用它們做爲請求資源使用生命週期同步
 */
@NonNull
public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
}
複製代碼

能夠看到Glide.with(context)有幾個重載的方法,Glide.with(context)方法主要的邏輯: 一、在1步驟中經過getRetriever獲取到在初始化Glide時建立的RequestManagerRetriever實例; 二、在2步驟中經過RequestManagerRetriever的get方法獲取RequestManager實例。 RequestManagerRetriever用於建立新的RequestManagers或從activity和fragment中檢索現有的RequestManagerside

Glide.with(context)最終調用getRetriever(context),而後再調用RequestManagerRetriever的實例get()方法,去獲取RequestManager對象:源碼分析

/**
 * getRetriever方法主要邏輯:
 * 一、在1步驟,會建立Glide實例而且初始化Glide實例,還會建立RequestManagerRetriever實例對象;
 * 二、在2步驟直接返回RequestManagerRetriever實例
 *
 * @param context
 * @return
 */
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) { // 1.2
    // Glide.get(context) 獲取Glide對象,包括初始化之類的配置
    Glide glide = Glide.get(context);//1
    // 經過Glide獲取RequestManagerRetriever
    // 可能你會驚訝在哪 初始化RequestManagerRetriever的,實際上是在GlideBuilder的build方法中
    RequestManagerRetriever requestManagerRetriever = glide.getRequestManagerRetriever();// 2
    return requestManagerRetriever;
}
複製代碼

一、 Glide.get(context) 獲取Glide對象包括初始化之類的配置,初始化後面會講GlideBiulder; 二、經過Glide對象獲取RequestManagerRetriever, 可能你會驚訝在哪 初始化RequestManagerRetriever的,實際上是在GlideBuilder的build方法中。動畫

接下來看一下調用RequestManagerRetriever 的get方法,也是有幾個重載;ui

/**
 * <p>
 * 上面getRetriever(context)方法,主要是構建Glide和RequestManagerRetriever
 * <p>
 * RequestManagerRetriever:一組靜態方法,用於建立新的RequestManagers或從活動和片斷中檢索現有的RequestManagers。
 * <p>
 * 這一步就是構建RequestManager:描述圖片加載請求管理者
 * <p>
 * <p>
 * 做用:主要是經過傳入的context構建RequestManager實例,固然你這裏可會從activity和fragment中獲取已經存在的RequestManager
 * 爲何須要context?主要是構建的RequestManager即請求管理,須要感知各組件的生命週期,例如:application、activity和fragment
 * <p>
 * 主要的邏輯:
 * 一、在1步驟中判斷是不是在主線程和是否是Application,若是咱們是在非主線程當中使用的Glide,那麼無論你是傳入的Activity仍是Fragment,都會被強制當成Application來處理
 * 二、在2步驟中直接當成Application處理;
 * 三、最後會經過RequestManager工廠(RequestManagerFactory)建立RequestManager實例
 * <p>
 * 最後:
 * 雖然get方法有多個重載其實邏輯的處理只有兩種:
 * 一、傳入的context是非Application參數的狀況:
 * 不論是傳入的context是Activity、FragmentActivity、v4包下的Fragment、仍是app包下的Fragment,
 * 最終的邏輯是同樣的,會向當前的Activity當中添加一個隱藏的Fragment。由於Glide須要感知加載的生命週期
 * 二、傳入的context是Application參數的狀況,或者是在後臺線程:
 * 若是傳入的context是Application或者是在後臺線程,直接就調用getApplicationManager()方法來獲取一個RequestManager對象
 * <p>
 * <p>
 *
 * <p>
 * 注意這裏的get方法都是單例的
 *
 * @param context
 * @return
 */
@NonNull
public RequestManager get(@NonNull Context context) {
    if (context == null) {
        throw new IllegalArgumentException("You cannot start a load on a null Context");
        //若是咱們是在非主線程當中使用的Glide,那麼無論你是傳入的Activity仍是Fragment,都會被強制當成Application來處理
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {//1
        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);// 2
}

@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
        return get(activity.getApplicationContext());
    } else {

        assertNotDestroyed(activity);
        // 獲取當前activity的FragmentManager,由於你須要爲當前activity添加隱藏的fragment
        FragmentManager fm = activity.getSupportFragmentManager();
        return supportFragmentGet(activity, fm, null, isActivityVisible(activity));
    }
}

 @NonNull
public RequestManager get(@NonNull Fragment fragment) {
    Preconditions.checkNotNull(fragment.getActivity(),
            "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
        return get(fragment.getActivity().getApplicationContext());
    } else {
        FragmentManager fm = fragment.getChildFragmentManager();
        return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
    }
}


@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
        return get(activity.getApplicationContext());
    } else {
        assertNotDestroyed(activity);
        android.app.FragmentManager fm = activity.getFragmentManager();
        return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
}

@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull View view) {
    if (Util.isOnBackgroundThread()) {
        return get(view.getContext().getApplicationContext());
    }

    Preconditions.checkNotNull(view);
    Preconditions.checkNotNull(view.getContext(),
            "Unable to obtain a request manager for a view without a Context");
    Activity activity = findActivity(view.getContext());
    // The view might be somewhere else, like a service.
    if (activity == null) {
        return get(view.getContext().getApplicationContext());
    }

    // Support Fragments.
    // Although the user might have non-support Fragments attached to FragmentActivity, searching
    // for non-support Fragments is so expensive pre O and that should be rare enough that we
    // prefer to just fall back to the Activity directly.
    if (activity instanceof FragmentActivity) {
        Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
        return fragment != null ? get(fragment) : get(activity);
    }

    // Standard Fragments.
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
        return get(activity);
    }
    return get(fragment);
}
複製代碼

一、上面getRetriever(context)方法,主要是構建Glide和RequestManagerRetriever 二、RequestManagerRetriever:一組靜態方法,用於建立新的RequestManagers或從活動和片斷中檢索現有的RequestManagers。 三、這一步就是構建RequestManager:描述圖片加載請求管理者 四、 做用:主要是經過傳入的context構建RequestManager實例,固然你這裏可會從activity和fragment中獲取已經存在的RequestManager 五、爲何須要context?主要是構建的RequestManager即請求管理,須要感知各組件的生命週期,例如:application、activity和fragment 六、主要的邏輯:url

  • 在1步驟中判斷是不是在主線程和是否是Application,若是咱們是在非主線程當中使用的Glide,那麼無論你是傳入的Activity仍是Fragment,都會被強制當成Application來處理
    • 在2步驟中直接當成Application處理;
    • 最後會經過RequestManager工廠(RequestManagerFactory)建立RequestManager實例 最後:雖然get方法有多個重載其實邏輯的處理只有兩種:傳入的context是非Application參數的狀況:不論是傳入的context是Activity、FragmentActivity、v4包下的Fragment、仍是app包下的Fragment,最終的邏輯是同樣的,會向當前的Activity當中添加一個隱藏的Fragment。由於Glide須要感知加載的生命週期, 傳入的context是Application參數的狀況,或者是在後臺線程: 若是傳入的context是Application或者是在後臺線程,直接就調用getApplicationManager()方法來獲取一個RequestManager對象 注意這裏的get方法都是單例的

能夠看到在get方法中經過supportFragmentGet方法和getSupportRequestManagerFragment構建隱藏的fragment:

/**
 * 主要邏輯:
 * 一、搜索是否已經添加了隱藏的Fragment到當前的Activity中,若是已經添加過了是由緩存的。
 * 二、若是在當前activity,已經添加了隱藏的Fragment,就嘗試從隱藏的Fragment中搜索RequestManager,
 * 若是沒有找到,就調用RequestManager工廠建立一個RequestManager,並添加到隱藏的Fragment中,而後返回RequestManager實例。
 * <p>
 * 注意:其實一個Activity就存在一個RequestManager,它們的關係是activity-SupportRequestManagerFragment-RequestManager一一對應
 *
 * @param context
 * @param fm
 * @param parentHint
 * @param isParentVisible
 * @return
 */
@NonNull
private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
                                          @Nullable Fragment parentHint, boolean isParentVisible) {
    // 搜索隱藏的Fragment
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    //從隱藏的Fragment搜索RequestManager
    RequestManager requestManager = current.getRequestManager();

    // 若是不存在就直接建立RequestManager並添加到隱藏的Fragment中緩存
    if (requestManager == null) {
        Glide glide = Glide.get(context);
        requestManager = factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(@NonNull final FragmentManager fm,
                                                                       @Nullable Fragment parentHint, boolean isParentVisible) {
    // 搜索是否已經添加了隱藏的Fragment
    SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);//1
    if (current == null) {
        // 從緩存中找
        current = pendingSupportRequestManagerFragments.get(fm);// 2

        // 仍是沒有找到,就直接建立一個Fragment
        if (current == null) {
            current = new SupportRequestManagerFragment();
            current.setParentFragmentHint(parentHint);

            // 若是當前activity正在顯示
            if (isParentVisible) {
                current.getGlideLifecycle().onStart();
            }

            // 加入緩存
            pendingSupportRequestManagerFragments.put(fm, current);
            // 開始fragment事務,標誌設置爲FRAGMENT_TAG
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}
複製代碼

一、搜索是否已經添加了隱藏的Fragment到當前的Activity中,若是已經添加過了是由緩存的。 二、若是在當前activity,已經添加了隱藏的Fragment,就嘗試從隱藏的Fragment中搜索RequestManager, 若是沒有找到,就調用RequestManager工廠建立一個RequestManager,並添加到隱藏的Fragment中,而後返回RequestManager實例。 注意:其實一個Activity就存在一個RequestManager,它們的關係是activity-SupportRequestManagerFragment-RequestManager一一對應

到此爲止就已經建立你好RequestManager了,也就是Glide的整個構建流程完畢,有的讀者可能會發現Glide的構建怎麼沒有,下面就開始。

你們還記得 getRetriever(context)方法中有這麼一行

Glide glide = Glide.get(context);
複製代碼

咱們來看看Glide get(@NonNull Context context)源碼

private static volatile Glide glide;
/**
 * Get the singleton.
* 單例雙重校驗
 */
@NonNull
public static Glide get(@NonNull Context context) {
    if (glide == null) {
        synchronized (Glide.class) {
            if (glide == null) {
                checkAndInitializeGlide(context);
            }
        }
    }
    return glide;
}

 private static void checkAndInitializeGlide(@NonNull Context context) {
    if (isInitializing) {
        throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
                + " use the provided Glide instance instead");
    }
    isInitializing = true;
    initializeGlide(context);
    isInitializing = false;
}
複製代碼

這個方法首先會檢查是否已經初始化了,由於在初始化Glide的線程中,一個或多個類能夠屢次調用Glide.get(context)。 若是沒有這個檢查,那些調用可能會觸發無限遞歸。就是避免重複初始化Glide對象

下面就是Glide初始化真正的邏輯:

/**
 * 首先找到@GlideModel註解生成的類GeneratedAppGlideModuleImpl
 * 
 * @param context
 * @param builder
 */
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    //獲取 applicationContext
    Context applicationContext = context.getApplicationContext();
    // 找到@GlideModel註解生成的類如GeneratedAppGlideModuleImpl
    GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
    /**
     * 
     * 
     * 會觸發每一個Module包括咱們自定義的Module中的applyOptions
     *
     * 在GlideBuilder中的biuld方法,每個默認配置都是判斷null,因此咱們能夠在咱們的自定義Module中修改Glide的配置
     *
     */
    if (annotationGeneratedModule != null) {
        annotationGeneratedModule.applyOptions(applicationContext, builder);
    }
    // 構建Glide
    Glide glide = builder.build(applicationContext);

    // 註冊組件,例如:替換默認HttpUrlConnection爲OkHttp以及其餘組件,固然這些是能夠經過註解來完成的,詳細請看官方的demo
    if (annotationGeneratedModule != null) {
        annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
}
複製代碼

首先找到@GlideModel註解生成的類GeneratedAppGlideModuleImpl,而且會觸發每一個Module包括咱們自定義的Module中的applyOptions,以便咱們修改Glide的默認配置。也就是說當你調用with方法時,就已經初始化Glide

再看看initializeGlide方法中初始化相關的配置GlideBiulder,這裏使用構建模式

// 構建Glide
 Glide glide = builder.build(applicationContext);
複製代碼

GlideBuilder:

private final Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions = new ArrayMap<>();
//  負責啓動負載並管理活動和緩存資源。
private Engine engine;
// Bitmap 複用池(享元模式)
private BitmapPool bitmapPool;

private ArrayPool arrayPool;

// 內存管理計算器或者策略
private MemorySizeCalculator memorySizeCalculator;
private MemoryCache memoryCache;

// Glide 資源線程池
private GlideExecutor sourceExecutor;

// 磁盤緩存線程池
private GlideExecutor diskCacheExecutor;
// 磁盤緩存工廠
private DiskCache.Factory diskCacheFactory;

// 網絡狀態監視器工廠
private ConnectivityMonitorFactory connectivityMonitorFactory;
private int logLevel = Log.INFO;
// 默認請求項
private RequestOptions defaultRequestOptions = new RequestOptions();
@Nullable
private RequestManagerFactory requestManagerFactory;
//執行動畫的線程池
private GlideExecutor animationExecutor;
private boolean isActiveResourceRetentionAllowed;
@Nullable
private List<RequestListener<Object>> defaultRequestListeners;
private boolean isLoggingRequestOriginsEnabled;
複製代碼

出了這些成員變量以外還有就是這些變量的setxx方法,我就不一一列出來,重點看看biuld方法。

/**
 * 其實每次判斷是否爲null就是不該該重複初始化,這也給咱們在自定義Model修改Glide的默認配置
 *
 * @param context
 * @return
 */
@NonNull
Glide build(@NonNull Context context) {
    // 網絡資源操做線程池
    if (sourceExecutor == null) {
        sourceExecutor = GlideExecutor.newSourceExecutor();
    }
    // 磁盤緩存操做線程池,不容許進行網絡操做
    if (diskCacheExecutor == null) {
        diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }
    // 執行動畫操做線程池
    if (animationExecutor == null) {
        animationExecutor = GlideExecutor.newAnimationExecutor();
    }

    //內存計算器,它嘗試根據某些常量和設備屏幕密度,寬度和高度智能地肯定給定設備的高速緩存大小。
    if (memorySizeCalculator == null) {
        memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }

    // 設備網絡監視器
    if (connectivityMonitorFactory == null) {
        connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }

    // bitmap 複用池
    if (bitmapPool == null) {
        int size = memorySizeCalculator.getBitmapPoolSize();
        if (size > 0) {
            bitmapPool = new LruBitmapPool(size);
        } else {
            bitmapPool = new BitmapPoolAdapter();
        }
    }

    // 暫時叫數組複用池
    if (arrayPool == null) {
        arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }

    // 內存緩存
    if (memoryCache == null) {
        memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }

    // 磁盤緩存工廠
    if (diskCacheFactory == null) {
        diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

    // 構建一個負責啓動和加載並管理活動和緩存資源。
    if (engine == null) {
        engine =
                new Engine(
                        memoryCache,
                        diskCacheFactory,
                        diskCacheExecutor,
                        sourceExecutor,
                        GlideExecutor.newUnlimitedSourceExecutor(),
                        animationExecutor,
                        isActiveResourceRetentionAllowed);
    }

    if (defaultRequestListeners == null) {
        defaultRequestListeners = Collections.emptyList();
    } else {
        defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }

    //一組靜態方法,用於建立新的RequestManagers或從活動和片斷中(Retriever)檢索現有的RequestManager。
    // RequestManager 描述圖片加載請求管理者,例如:感知聲明週期取消請求
    RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory);

    // 建立GLide對象
    return new Glide(
            context,
            engine,
            memoryCache,
            bitmapPool,
            arrayPool,
            requestManagerRetriever,
            connectivityMonitorFactory,
            logLevel,
            defaultRequestOptions.lock(),
            defaultTransitionOptions,
            defaultRequestListeners,
            isLoggingRequestOriginsEnabled);
}
複製代碼

其實Glide的構建是至關複雜的,包括各類線程池的配置以及各類複用池的構建,經過GlideBuilder構建Glide,RequestManager見名思意就是檢索RequestManager即在activity或者Fragment中檢索是否存在,不然直接建立。

相關文章
相關標籤/搜索