天天看點

Glide源碼分析

使用

官方給出的簡單使用的例子:

// For a simple view:
@Override public void onCreate(Bundle savedInstanceState) {
  ...
  ImageView imageView = (ImageView) findViewById(R.id.my_image_view);

  GlideApp.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}

// For a simple image list:
@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);

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

  return myImageView;
}
           

其中最主要的就是部分就是:

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

with()

首先來看with():

public static RequestManager with(Context context) {
  RequestManagerRetriever retriever = RequestManagerRetriever.get();
  return retriever.get(context);
}

public static RequestManager with(Activity activity) {
  RequestManagerRetriever retriever = RequestManagerRetriever.get();
  return retriever.get(activity);
}

public static RequestManager with(FragmentActivity activity) {
  RequestManagerRetriever retriever = RequestManagerRetriever.get();
  return retriever.get(activity);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
  RequestManagerRetriever retriever = RequestManagerRetriever.get();
  return retriever.get(fragment);
}

public static RequestManager with(Fragment fragment) {
  RequestManagerRetriever retriever = RequestManagerRetriever.get();
  return retriever.get(fragment);
}
           

可以看到有五個重載方法,都調用了RequestManagerRetriever的get(),去擷取一個RequestManagerRetriever的唯一執行個體:

/** The singleton instance of RequestManagerRetriever. */
    // 單例模式中的餓漢式
    private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever();

    /**
     * Retrieves and returns the RequestManagerRetriever singleton.
     */
    public static RequestManagerRetriever get() {
        return INSTANCE;
    }
           

然後利用擷取到的這個RequestManagerRetriever,調用get():

public RequestManager get(Context 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);
    }

    public RequestManager get(FragmentActivity activity) {
        if (Util.isOnBackgroundThread()) {
            return get(activity.getApplicationContext());
        } else {
            assertNotDestroyed(activity);
            FragmentManager fm = activity.getSupportFragmentManager();
            return supportFragmentGet(activity, fm);
        }
    }

    public RequestManager get(Fragment fragment) {
        if (fragment.getActivity() == null) {
            throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
        }
        if (Util.isOnBackgroundThread()) {
            return get(fragment.getActivity().getApplicationContext());
        } else {
            FragmentManager fm = fragment.getChildFragmentManager();
            return supportFragmentGet(fragment.getActivity(), fm);
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public RequestManager get(Activity activity) {
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            return get(activity.getApplicationContext());
        } else {
            assertNotDestroyed(activity);
            android.app.FragmentManager fm = activity.getFragmentManager();
            return fragmentGet(activity, fm);
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public RequestManager get(android.app.Fragment fragment) {
        if (fragment.getActivity() == null) {
            throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
        }
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return get(fragment.getActivity().getApplicationContext());
        } else {
            android.app.FragmentManager fm = fragment.getChildFragmentManager();
            return fragmentGet(fragment.getActivity(), fm);
        }
    }
           

同樣是五個重載方法,我們來看其中一個:

// 這個fragment是v4包下的Fragment
    public RequestManager get(Fragment fragment) {
        if (fragment.getActivity() == null) {
            // 判斷fragment是否已經加添加到父容器上,如果沒有抛出異常
            throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
        }
        if (Util.isOnBackgroundThread()) {
            // 如果是在子線程中,傳回一個由ApplicationContext建構的單例的RequestManager
            return get(fragment.getActivity().getApplicationContext());
        } else {
            // 在主線程中的話,調用supportFragmentGet(),并且入參是目前fragment所在的Activity和FragmentManager
            FragmentManager fm = fragment.getChildFragmentManager();
            return supportFragmentGet(fragment.getActivity(), fm);
        }
    }
           

繼續進入supportFragmentGet():

RequestManager supportFragmentGet(Context context, final FragmentManager fm) {
        // 判斷在目前的FragmentManager中是否已經加入了SupportRequestManagerFragment
        SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(TAG);
        if (current == null) {
            // 判斷緩存中是否有該FragmentManager對應的SupportRequestManagerFragment
            current = pendingSupportRequestManagerFragments.get(fm);
            if (current == null) {
                // 如果都沒有,就建立一個SupportRequestManagerFragment,加入到目前的FragmentManager中
                current = new SupportRequestManagerFragment();
                pendingSupportRequestManagerFragments.put(fm, current);
                fm.beginTransaction().add(current, TAG).commitAllowingStateLoss();
                handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
            }
        }
        // 判斷目前的FragmentManager是否有RequestManager
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            // 如果沒有的話,建立一個RequestManager
            requestManager = new RequestManager(context, current.getLifecycle());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }
           

這裡我們來看一下SupportRequestManagerFragment究竟是什麼:

public class SupportRequestManagerFragment extends Fragment {
    private RequestManager requestManager;
    private final ActivityFragmentLifecycle lifecycle;

    public SupportRequestManagerFragment() {
        this(new ActivityFragmentLifecycle());
    }

    // For testing only.
    @SuppressLint("ValidFragment")
    public SupportRequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
        this.lifecycle = lifecycle;
    }

    /**
     * Sets the current {@link com.bumptech.glide.RequestManager}.
     *
     * @param requestManager The manager to set.
     */
    public void setRequestManager(RequestManager requestManager) {
        this.requestManager = requestManager;
    }

    ActivityFragmentLifecycle getLifecycle() {
        return lifecycle;
    }

    /**
     * Returns the current {@link com.bumptech.glide.RequestManager} or null if none is set.
     */
    public RequestManager getRequestManager() {
        return requestManager;
    }

    @Override
    public void onStart() {
        super.onStart();
        lifecycle.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
        lifecycle.onStop();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        lifecycle.onDestroy();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        // If an activity is re-created, onLowMemory may be called before a manager is ever set.
        // See #329.
        if (requestManager != null) {
            requestManager.onLowMemory();
        }
    }
}
           

代碼很簡單,我們可以看出來SupportRequestManagerFragment建立的時候建立了一個ActivityFragmentLifecycle,用來回調SupportRequestManagerFragment的生命周期事件。

當父容器的生命周期改變的時候,我們目前的這個SupportRequestManagerFragment生命周期也會改變,然後就會回調ActivityFragmentLifecycle對應的方法。

回到上面

requestManager = new RequestManager(context, current.getLifecycle());

,确實這裡就把這個ActivityFragmentLifecycle作為構造函參數遞到了RequestManager中。

至此,我們通過

Glide.with()

擷取了一個RequestManager對象。

生命周期事件的傳遞圖:

Glide源碼分析

load()

load()也有很多重載:

public DrawableTypeRequest<String> load(String string) {
        return (DrawableTypeRequest<String>) fromString().load(string);
    }

    public DrawableTypeRequest<Uri> load(Uri uri) {
        return (DrawableTypeRequest<Uri>) fromUri().load(uri);
    }

    public DrawableTypeRequest<File> load(File file) {
        return (DrawableTypeRequest<File>) fromFile().load(file);
    }

    public DrawableTypeRequest<Integer> load(Integer resourceId) {
        return (DrawableTypeRequest<Integer>) fromResource().load(resourceId);
    }

    public DrawableTypeRequest<URL> load(URL url) {
        return (DrawableTypeRequest<URL>) fromUrl().load(url);
    }

    public DrawableTypeRequest<byte[]> load(byte[] model) {
        return (DrawableTypeRequest<byte[]>) fromBytes().load(model);
    }
    ……
           

最終都建立了一個DrawableTypeRequest對象,接着進入into()。

into()

/**
     * Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into the view, and frees
     * any resources Glide may have previously loaded into the view so they may be reused.
     *
     * @see Glide#clear(android.view.View)
     *
     * @param view The view to cancel previous loads for and load the new resource into.
     * @return The {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link ImageView}.
     */
    public Target<TranscodeType> into(ImageView view) {
        // 判斷是否在主線程
        Util.assertMainThread();
        if (view == null) {
            // 對ImageView判空
            throw new IllegalArgumentException("You must pass in a non null View");
        }

        if (!isTransformationSet && view.getScaleType() != null) {
            // 根據scaleType做一些處理
            switch (view.getScaleType()) {
                case CENTER_CROP:
                    applyCenterCrop();
                    break;
                case FIT_CENTER:
                case FIT_START:
                case FIT_END:
                    applyFitCenter();
                    break;
                //$CASES-OMITTED$
                default:
                    // Do nothing.
            }
        }

        return into(glide.buildImageViewTarget(view, transcodeClass));
    }
           

進而調用into()的重載:

/**
     * Set the target the resource will be loaded into.
     *
     * @see Glide#clear(com.bumptech.glide.request.target.Target)
     *
     * @param target The target to load the resource into.
     * @return The given target.
     */
    public <Y extends Target<TranscodeType>> Y into(Y target) {
        // 判斷是否在主線程
        Util.assertMainThread();
        if (target == null) {
            // 非空判斷
            throw new IllegalArgumentException("You must pass in a non null Target");
        }
        if (!isModelSet) {
            // 是否能夠加載該種資源
            throw new IllegalArgumentException("You must first set a model (try #load())");
        }
        // 擷取改目标之前的請求
        Request previous = target.getRequest();

        if (previous != null) {
            // 如果之前的請求不為空,則清除并且從requestTracker移除
            previous.clear();
            requestTracker.removeRequest(previous);
            previous.recycle();
        }
        // 建立一個Request
        Request request = buildRequest(target);
        // 給該目标設定Request
        target.setRequest(request);
        // 将該目标加入生命周期的監聽器集合中
        lifecycle.addListener(target);
        // 開始發起請求
        requestTracker.runRequest(request);

        return target;
    }
           

into()的流程圖如下:

Glide源碼分析

接着進入runRequest():

/**
     * Starts tracking the given request.
     */
    // 開始追蹤該請求
    public void runRequest(Request request) {
        requests.add(request);
        if (!isPaused) {
            // 非暫停狀态,開始請求
            request.begin();
        } else {
            // 否則加入暫停隊列
            pendingRequests.add(request);
        }
    }
           

進入begin():

public void begin() {
        startTime = LogTime.getLogTime();
        if (model == null) {
            onException(null);
            return;
        }
        // 修改狀态
        status = Status.WAITING_FOR_SIZE;
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            // 如果尺寸有效,進入onSizeReady()
            onSizeReady(overrideWidth, overrideHeight);
        } else {
            // 尺寸無效,先擷取尺寸
            target.getSize(this);
        }

        if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
            // 做真正請求前的準備,比如設定占位圖檔
            target.onLoadStarted(getPlaceholderDrawable());
        }
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("finished run method in " + LogTime.getElapsedMillis(startTime));
        }
    }
           

進入onSizeReady():

/**
     * A callback method that should never be invoked directly.
     */
    @Override
    public void onSizeReady(int width, int height) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
        }
        if (status != Status.WAITING_FOR_SIZE) {
            return;
        }
        status = Status.RUNNING;

        width = Math.round(sizeMultiplier * width);
        height = Math.round(sizeMultiplier * height);

        ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
        final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);

        if (dataFetcher == null) {
            onException(new Exception("Got null fetcher from model loader"));
            return;
        }
        ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
        }
        loadedFromMemoryCache = true;
        loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                priority, isMemoryCacheable, diskCacheStrategy, this);
        loadedFromMemoryCache = resource != null;
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
        }
    }
           

其中主要做的一件事情就是調用Engine的load():

public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
            DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
            Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
        // 判斷是否是主線程
        Util.assertMainThread();
        long startTime = LogTime.getLogTime();

        final String id = fetcher.getId();
        // 生成一個EngineKey
        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
                loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
                transcoder, loadProvider.getSourceEncoder());
        // 從記憶體緩存中擷取EngineResource
        EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
        if (cached != null) {
            cb.onResourceReady(cached);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Loaded resource from cache", startTime, key);
            }
            return null;
        }
        // 從活躍的資源中擷取
        EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
        if (active != null) {
            cb.onResourceReady(active);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Loaded resource from active resources", startTime, key);
            }
            return null;
        }
        // 擷取Map中擷取已經存在的改key對應的EngineJob
        EngineJob current = jobs.get(key);
        if (current != null) {
            current.addCallback(cb);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Added to existing load", startTime, key);
            }
            return new LoadStatus(cb, current);
        }
        // 如果以上都不滿足,建立一個該key對應的EngineJob,它的作用是排程DecodeJob,添加,移除資源回調,并notify回調
        EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
        // 建立一個DecodeJob,處理來自緩存或者原始的資源,應用轉換動畫以及transcode。
        DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
                transcoder, diskCacheProvider, diskCacheStrategy, priority);
        EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
        // 存儲該EngineJob
        jobs.put(key, engineJob);
        engineJob.addCallback(cb);
        // 開啟EngineRunnable
        engineJob.start(runnable);

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Started new load", startTime, key);
        }
        // 傳回一個LoadStatus,其中記錄着EngineJob和一個ResourceCallback
        return new LoadStatus(cb, engineJob);
    }
           

進入start():

public void start(EngineRunnable engineRunnable) {
        this.engineRunnable = engineRunnable;
        // diskCacheService是一個線程池,預設的是一個先進先出同時有優先級的線程池FifoPriorityThreadPoolExecutor
        future = diskCacheService.submit(engineRunnable);
    }
           

線程池執行EngineRunnable,會調用EngineRunnable的run():

@Override
    public void run() {
        if (isCancelled) {
            // 被取消,直接結束
            return;
        }

        Exception exception = null;
        Resource<?> resource = null;
        try {
            resource = decode();
        } catch (Exception e) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "Exception decoding", e);
            }
            exception = e;
        }

        if (isCancelled) {
            if (resource != null) {
                // 被取消時,資源回收
                resource.recycle();
            }
            return;
        }

        if (resource == null) {
            // 失敗處理
            onLoadFailed(exception);
        } else {
            // 成功處理
            onLoadComplete(resource);
        }
    }
           

進入decode():

private Resource<?> decode() throws Exception {
        if (isDecodingFromCache()) {
            // 從緩存中擷取
            return decodeFromCache();
        } else {
            // 從真正的來源處擷取
            return decodeFromSource();
        }
    }
           

decodeFromSource()在一連串函數調用鍊之後會進入DecodeJob的decodeSource():

private Resource<T> decodeSource() throws Exception {
        Resource<T> decoded = null;
        try {
            long startTime = LogTime.getLogTime();
            // 加載資源
            final A data = fetcher.loadData(priority);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Fetched data", startTime);
            }
            if (isCancelled) {
                return null;
            }
            // 解析資源
            decoded = decodeFromSourceData(data);
        } finally {
            // 最終回收資源
            fetcher.cleanup();
        }
        return decoded;
    }
           

進入DataFetcher的loadData(),根據來源的不同有不同的實作,我們這裡看下HttpUrlFetcher,通過一個url擷取資源:

@Override
    public InputStream loadData(Priority priority) throws Exception {
        return loadDataWithRedirects(glideUrl.toURL(),  /*redirects*/, null /*lastUrl*/);
    }

    private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl) throws IOException {
        // 判斷是否重定向的次數太多
        if (redirects >= MAXIMUM_REDIRECTS) {
            throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
        } else {
            // Comparing the URLs using .equals performs additional network I/O and is generally broken.
            // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
            try {
                if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
                    throw new IOException("In re-direct loop");
                }
            } catch (URISyntaxException e) {
                // Do nothing, this is best effort.
            }
        }
        // 配置HttpURLConnection
        urlConnection = connectionFactory.build(url);
        urlConnection.setConnectTimeout();
        urlConnection.setReadTimeout();
        urlConnection.setUseCaches(false);
        urlConnection.setDoInput(true);

        // Connect explicitly to avoid errors in decoders if connection fails.
        // 開啟網絡連接配接
        urlConnection.connect();
        if (isCancelled) {
            // 如果取消,傳回null
            return null;
        }
        // 擷取響應碼
        final int statusCode = urlConnection.getResponseCode();
        if (statusCode /  == ) {
            // 如果成功,從服務端擷取流
            stream = urlConnection.getInputStream();
            return stream;
        } else if (statusCode /  == ) {
            // 重定向
            String redirectUrlString = urlConnection.getHeaderField("Location");
            if (TextUtils.isEmpty(redirectUrlString)) {
                throw new IOException("Received empty or null redirect url");
            }
            URL redirectUrl = new URL(url, redirectUrlString);
            return loadDataWithRedirects(redirectUrl, redirects + , url);
        } else {
            // 如果失敗,抛出異常
            if (statusCode == -) {
                throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
            }
            throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
        }
    }
           

在decodeFromSourceData()中如果需要磁盤緩存的話,會進行磁盤緩存:

private Resource<T> decodeFromSourceData(A data) throws IOException {
        final Resource<T> decoded;
        if (diskCacheStrategy.cacheSource()) {
            decoded = cacheAndDecodeSourceData(data);
        } else {
            long startTime = LogTime.getLogTime();
            decoded = loadProvider.getSourceDecoder().decode(data, width, height);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Decoded from source", startTime);
            }
        }
        return decoded;
    }
           

接着回到EngineRunnable的run(),進入成功處理的方法:

private void onLoadComplete(Resource resource) {
        manager.onResourceReady(resource);
    }
           

這裡的manager就是一個EngineJob,這裡就回調了EngineJob的onResourceReady():

@Override
    public void onResourceReady(final Resource<?> resource) {
        this.resource = resource;
        MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
    }
           

MAIN_THREAD_HANDLER是一個主線程的Handler:

private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
           

用來切換到主線程,給對應的target發送成功或者失敗的消息:

private static class MainThreadCallback implements Handler.Callback {

        @Override
        public boolean handleMessage(Message message) {
            if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
                EngineJob job = (EngineJob) message.obj;
                if (MSG_COMPLETE == message.what) {
                    job.handleResultOnMainThread();
                } else {
                    job.handleExceptionOnMainThread();
                }
                return true;
            }

            return false;
        }
    }
           

進入handleResultOnMainThread():

private void handleResultOnMainThread() {
        if (isCancelled) {
            // 已經取消,回收資源
            resource.recycle();
            return;
        } else if (cbs.isEmpty()) {
            throw new IllegalStateException("Received a resource without any callbacks to notify");
        }
        engineResource = engineResourceFactory.build(resource, isCacheable);
        hasResource = true;

        // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
        // synchronously released by one of the callbacks.
        engineResource.acquire();
        listener.onEngineJobComplete(key, engineResource);

        for (ResourceCallback cb : cbs) {
            if (!isInIgnoredCallbacks(cb)) {
                engineResource.acquire();
                // 回調ResourceCallback的onResourceReady()
                // 在其中對應target會去處理資源
                // 比如給ImageView設定下載下傳好的圖檔
                cb.onResourceReady(engineResource);
            }
        }
        // Our request is complete, so we can release the resource.
        engineResource.release();
    }
           

EngineJob的load()流程圖:

Glide源碼分析

參考:Glide 源碼分析