1. 程式人生 > >android其實很簡單 -- Glide簡單分析

android其實很簡單 -- Glide簡單分析

最近在使用Glide,遇到不少不解的問題

  • 生命週期是如何繫結的
  • 快取策略

從官方的例子開始

    // 這裡的this我們假設為Activity
    Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);

with

    // with返回了一個RequestManager,RequestManager將acitivity生命週期與request繫結
    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/Glide.java#L668
public static RequestManager with(Activity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); } // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java#L120 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); } } // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java#L167 @TargetApi(Build.VERSION_CODES.HONEYCOMB) RequestManager fragmentGet(Context context, android.app.FragmentManager fm) { RequestManagerFragment current = getRequestManagerFragment(fm); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { requestManager = new RequestManager(context, current.getGlideLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); } return requestManager; } // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java#L152 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) { RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { current = pendingRequestManagerFragments.get(fm); if (current == null) { // 這裡生成了一個Fragment,通過過載其生命週期回撥,就可以繫結activity的生命週期 current = new RequestManagerFragment(); pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; } // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestManagerFragment.java @Override public void onStart() { super.onStart(); lifecycle.onStart(); } @Override public void onStop() { super.onStop(); lifecycle.onStop(); } @Override public void onDestroy() { super.onDestroy(); lifecycle.onDestroy(); }

load

    // 開始載入圖片啦,首先生成了一個DrawableTypeRequest
    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/RequestManager.java#L283
    public DrawableTypeRequest<String> load(String string) {
        return (DrawableTypeRequest<String>) fromString().load(string);
    }

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/RequestManager.java#L303
    public DrawableTypeRequest<String> fromString() {
        return loadGeneric(String.class);
    }

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/RequestManager.java#L624
    private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
        ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
        ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
                Glide.buildFileDescriptorModelLoader(modelClass, context);
        if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
            throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
                    + " which there is a registered ModelLoader, if you are using a custom model, you must first call"
                    + " Glide#register with a ModelLoaderFactory for your custom model class");
        }

        return optionsApplier.apply(
                new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                        glide, requestTracker, lifecycle, optionsApplier));
    }

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java#L30
    // DrawableTypeRequest繼承自DrawableRequestBuilder,通過optionsApplier.apply可以調整載入引數
    public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {...}

into

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java#L456
    // into正式開始載入圖片,包括下載快取顯示
    @Override
        public Target<GlideDrawable> into(ImageView view) {
        return super.into(view);
    }

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java#L682
    public Target<TranscodeType> into(ImageView view) {
        Util.assertMainThread();
        if (view == null) {
            throw new IllegalArgumentException("You must pass in a non null View");
        }

        if (!isTransformationSet && view.getScaleType() != null) {
            switch (view.getScaleType()) {
                case CENTER_CROP:
                    applyCenterCrop();
                    break;
                case FIT_CENTER:
                case FIT_START:
                case FIT_END:
                    applyFitCenter();
                    break;
                //$CASES-OMITTED$
                default:
                    // Do nothing.
            }
        }
        // 這裡buildImageViewTarget返回了ImageViewTarget(確切來說是子類),封裝了一個ImageView,在request結束後會設定對應的image
        return into(glide.buildImageViewTarget(view, transcodeClass));
    }

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java#L648
    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) {
            previous.clear();
            requestTracker.removeRequest(previous);
            previous.recycle();
        }

        // 這裡的buildRequest最後會返回一個GenericRequest
        // (程式碼很長,通過窺屏知道的http://blog.csdn.net/guolin_blog/article/details/53939176/)
        Request request = buildRequest(target);
        target.setRequest(request);
        lifecycle.addListener(target);
        requestTracker.runRequest(request);

        return target;
    }

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java#L34
    public void runRequest(Request request) {
        requests.add(request);
        if (!isPaused) {
            // 請求從這裡開始發起,搜尋記憶體,磁碟快取,及網路請求
            request.begin();
        } else {
            pendingRequests.add(request);
        }
    }

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/request/GenericRequest.java#L261
    @Override
    public void begin() {
        startTime = LogTime.getLogTime();
        if (model == null) {
            onException(null);
            return;
        }

        status = Status.WAITING_FOR_SIZE;
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            // 真實的請求從這裡開始,這個名字好坑
            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));
        }
    }

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/request/GenericRequest.java#L425
    @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("Failed to load model: \'" + model + "\'"));
            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;
        // 這裡進入engine的載入流程
        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));
        }
    }

    // https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/load/engine/Engine.java
    // 簡單看下,主要是查快取及網路請求了
    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 key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
                loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
                transcoder, loadProvider.getSourceEncoder());

        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;
        }

        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);
        }

        EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
        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);
        jobs.put(key, engineJob);
        engineJob.addCallback(cb);
        engineJob.start(runnable);

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Started new load", startTime, key);
        }
        return new LoadStatus(cb, engineJob);
    }

相關推薦

android其實簡單 -- Glide簡單分析

最近在使用Glide,遇到不少不解的問題 生命週期是如何繫結的 快取策略 從官方的例子開始 // 這裡的this我們假設為Activity Glide.with(this).load("http://goo.gl/gEgYUd").

android其實簡單--記憶體相關

記憶體洩漏 java是垃圾回收語言,無需開發者管理記憶體分配 邏輯上的失誤導致記憶體洩漏:當應用不再需要這個物件的時候仍未釋放該物件的所有應用 1.Context,由於Content包含了大量的記憶體引用。 全域性的process的static引用act

Android 熱修復其實簡單

一、什麼是熱修復 熱修復說白了就是”打補丁”,比如你們公司上線一個app,使用者反應有重大bug,需要緊急修復。如果按照通  常做法,那就是程式猿加班搞定bug,然後測試,重新打包併發布。這樣帶來的問題就是成本高,效率低。於是,熱  修復就應運而生.一般通過事先設定的介面從

Android適配其實簡單

本來寫了很長一段文字,來吹捧下本適配方案簡單易用效果好,最終還是刪掉了,直接上傳程式碼,說明下用法,大家可自行下載,和網上各種適配方案進行對比,擇優選取適配方案。(本適配方案目前博主已運用於幾百萬日活app上,沒有出現任何適配上的問題,此方案也是從網上摘取下來,

android js呼叫java 並取得java當中的返回值返回到js的做法其實簡單,打包後出現問題記得修改proguard.cfg檔案

package wst.webview; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.View; import andr

將圖片轉換成文字其實簡單

很多朋友們會在各大論壇或者網站上看到一些比較喜歡的文章或者是文字,但是很多文章會受到版權的限制或者其他的各種原因導致無法直接下載,就得不到自己喜歡的那些文字了。 這裏給大家發一個福利,就是我們的捷速OCR文字識別軟件,只要你把你想要的文字用截屏截成圖片,然後在捷速中進行文字識別,立

手把手教你開發chrome擴展一:開發Chrome Extenstion其實簡單

evernote 把手 擴展 data文件夾 現在 效果 界面 nag blog 手把手教你開發chrome擴展一:開發Chrome Extenstion其實很簡單 手把手教你開發Chrome擴展二:為html添加行為 手把手教你開發Chrome擴展三:關於本地存儲數據

這麽說吧,java線程池的實現原理其實簡單

arr nan ads stop shc 線程異常 fixed 響應 submit 好處 : 線程是稀缺資源,如果被無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,合理的使用線程池對線程進行統一分配、調優和監控,有以下好處: 1、降低資源消耗; 2、提高響應速度;

補碼(為什麽按位取反再加一):告訴你一個其實簡單的問題

滿足 所有 我們 進位 數字 樂意 如果 二進制 關系   首先,閱讀這篇文章的你,肯定是一個在網上已經糾結了很久的讀者,因為你查閱了所有你能查到的資料,然後他們都會很耐心的告訴你,補碼:就是按位取反,然後加一。準確無誤,毫無破綻。但是,你搜遍了所有俯拾即是而且準確無誤的答

SQL註入其實簡單,別一不留神就被利用了

SQL註入 sqlmap SQL防註入 SQL註入這個詞相信大家應該都不陌生,而且每年都會有這樣子的事情發生,下面我先帶大家回憶11年兩期起比較經典的案例事件: 1、SONY索尼事件2011年4月,著名的×××組織Anonymous***SONY一個網站,一星期後才被發現7千萬的用戶個人信息,其中

Android bitmap旋轉、平移簡單幾何變換方便

1.順時針旋轉90度 byte[] tmp = os.toByteArray(); Bitmap bmpt = BitmapFactory.decodeByteArray(tmp, 0,tmp.length); Matrix matrix = new Matrix(); matrix

漢諾塔問題其實簡單

推出 class 回溯思想 除了 source 問題 容易 假設 為我 首先上代碼 1 def hanoi_move(n, source, dest, intermediate): 2 if n >= 1: # 遞歸出口,只剩一個盤子 3

面向物件程式設計其實簡單——Python 面向物件(初級篇)

概述 面向過程:根據業務邏輯從上到下寫壘程式碼 函式式:將某功能程式碼封裝到函式中,日後便無需重複編寫,僅呼叫函式即可 面向物件:對函式進行分類和封裝,讓開發“更快更好更強...” 面向過程程式設計最易被初學者接受,其往往用一長段程式碼來實現指定功能,開發過

dubbo其實簡單,就是一個遠端服務呼叫的框架(1)

dubbo專題」dubbo其實很簡單,就是一個遠端服務呼叫的框架(1) 一、dubbo是什麼? 1)本質:一個Jar包,一個分散式框架,,一個遠端服務呼叫的分散式框架。 既然是新手教學,肯定很多同學不明白什麼是分散式和遠端服務呼叫,為什麼要分散式,為什麼要遠端呼叫。我簡單畫個對比圖說明(

初學XPath,其實簡單

XPath 是一門在 XML 文件中查詢資訊的語言。XPath 用於在 XML 文件中通過元素和屬性進行導航。 (我的理解:XPath 就是一個用來查詢xml節點的路徑語言,一個路徑字串語法) XML 例項文件 我們將在下面的例子中使用這個 XML 文件。 <?xml vers

從壹開始前後端分離 [ Vue2.0+.NET Core2.1] 二十三║Vue實戰:Vuex 其實簡單

前言 哈嘍大家週五好,馬上又是一個週末了,下週就是中秋了,下下週就是國慶啦,這裡先祝福大家一個比一個假日嗨皮啦~~轉眼我們的專題已經寫了第 23 篇了,好幾次都堅持不下去想要中斷,不過每當看到群裡的交流,看到部落格下邊好多小夥伴提出問題,我又燃起了鬥志,不過這兩天感冒了,所以更新的比較晚,這裡也提醒大家,節

Android安卓APK反編譯分析簡單修改內容、二次打包簽名

一、需求:想要修改一個apk裡面一串字串 環境: dex2jar----https://github.com/pxb1988/dex2jar/ JD-GUI----http://jd.benow.ca/ jdk1.8.0環境 二、先反編譯解包分析: (明

新手也能看懂,訊息佇列其實簡單

該文已加入開源專案:JavaGuide(一份涵蓋大部分Java程式設計師所需要掌握的核心知識的文件類專案,Star 數接近 16k)。地址:https://github.com/Snailclimb/JavaGuide. 本文內容思維導圖: 訊息佇列其實很簡單   “RabbitMQ?”“Kafk

Spring與Struts2的整合其實簡單

下面是整合步驟 一、複製jar檔案。 把struts2-spring-plugin-..*.jar和spring.jar複製到Web工程的WEB-INF/lib目錄下,並且還需要複製commons-logging.jar。 二、配置Struts.objectFactory