Glide源碼解析

一、Glide使用

Glide.with(getApplicationContext()) // 指定Context
        .load(url)// 指定圖片的URL
        .placeholder(R.mipmap.ic_launcher)// 指定圖片未成功加載前顯示的圖片
        .error(R.mipmap.ic_launcher)// 指定圖片加載失敗顯示的圖片
        .override(300, 300)//指定圖片的尺寸
        .fitCenter()//指定圖片縮放類型為
        .centerCrop()// 指定圖片縮放類型為
        .skipMemoryCache(true)// 跳過內(nèi)存緩存
        .diskCacheStrategy(DiskCacheStrategy.NONE)//跳過磁盤緩存
        .diskCacheStrategy(DiskCacheStrategy.SOURCE)//僅僅只緩存原來的全分辨率的圖像
        .diskCacheStrategy(DiskCacheStrategy.RESULT)//僅僅緩存最終的圖像
        .diskCacheStrategy(DiskCacheStrategy.ALL)//緩存所有版本的圖像
        .priority(Priority.HIGH)//指定優(yōu)先級凰盔,但是它不能保證所有的圖片都會按照所要求的順序加載墓卦。
         //優(yōu)先級排序:IMMEDIATE > HIGH > NORMAL > LOW
        .into(imageView);//指定顯示圖片的Imageview

二、with方法(獲取RequestManager)

with有很多重載方法户敬,可以傳入Context落剪、Activity、FragmentActivity尿庐、Fragment等忠怖,這么設(shè)計(jì)是為了靈活的根據(jù)當(dāng)前的上下文和組件對加載圖片的生命周期進(jìn)行管理,使圖片加載和組件的生命周期相掛鉤

    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(Fragment fragment) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(fragment);
    }

首先會調(diào)用RequestManagerRetriever的get方法獲取一個RequestManagerRetriever抄瑟,這個類主要是用來產(chǎn)生我們需要的RequestManager

public class RequestManagerRetriever implements Handler.Callback {

    public static RequestManagerRetriever get() {
        return INSTANCE;
    }

    private RequestManager getApplicationManager(Context context) {
        // Either an application context or we're on a background thread.
        if (applicationManager == null) {
            synchronized (this) {
                if (applicationManager == null) {
                    // 一般情況下是通過添加到activity的fragment來監(jiān)聽 pause/resume 
                    // 但是凡泣,在這種情況下傳入的是application,必須使用ApplicationLifecycle
                    applicationManager = new RequestManager(context.getApplicationContext(),
                            new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                }
            }
        }

        return applicationManager;
    }

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

傳入Activity或Fragment類型的Context 時get處理方式

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

    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);
        }
    }
    // fragment和Activity都會調(diào)用fragmentGet獲取一個RequestManager
    RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
        // 一個沒有ui的fragment皮假,用它來監(jiān)聽activity或fragment的生命周期
        RequestManagerFragment current = getRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

    RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
        // 查找RequestManagerFragment是否已經(jīng)存在并添加到activity或非讓夢
        RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        if (current == null) {
            // 緩存中查找
            current = pendingRequestManagerFragments.get(fm);
            if (current == null) {
                current = new RequestManagerFragment();
                pendingRequestManagerFragments.put(fm, current);
                // 添加RequestManagerFragment
                fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
            }
        }
        return current;
    }

RequestManagerFragment部分源碼

public class RequestManagerFragment extends Fragment {
    private final ActivityFragmentLifecycle lifecycle;
    private RequestManager 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 onTrimMemory(int level) {
        if (requestManager != null) {
            requestManager.onTrimMemory(level);
        }
    }

    @Override
    public void onLowMemory() {
        if (requestManager != null) {
            requestManager.onLowMemory();
        }
    }
} 

三鞋拟、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);
    }

也有很多的重載方法,因?yàn)間lide支持多種的圖片來源惹资,加載的時候需要不同的參數(shù)類型對應(yīng)不同的來源
load方法的返回值都是DrawableTypeRequest贺纲,這個類是glide中加載圖片的request請求處理類,DrawableTypeRequest繼承自DrawableRequestBuilder褪测,從名字可以看出是一個構(gòu)造器模式猴誊,會做一些request的參數(shù)構(gòu)建:

DrawableRequestBuilder.png

下面再看一下load中調(diào)用的fromString()方法

    public DrawableTypeRequest<String> fromString() {
        return loadGeneric(String.class);
    }

    private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
         // 創(chuàng)建兩個ModelLoader,ModelLoader主要作用是把數(shù)據(jù)來源加載成原始數(shù)據(jù)
        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("");
        }

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

四侮措、into方法

1懈叹、構(gòu)建一個target

into方法的最終實(shí)現(xiàn)是在GenericRequestBuilder類中

    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) {
            // 進(jìn)行圖片裁剪 
            switch (view.getScaleType()) {
                case CENTER_CROP:
                    applyCenterCrop();
                    break;
                case FIT_CENTER:
                case FIT_START:
                case FIT_END:
                    applyFitCenter();
                    break;
                default:
            }
        } 
        // buildImageViewTarget 創(chuàng)建一個target對象,將圖片最后要顯示的目標(biāo)封裝成一個target
        return into(glide.buildImageViewTarget(view, transcodeClass));
    }
    //buildImageViewTarget會通過一個imageViewTargetFactory工廠類創(chuàng)建target
    <R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
        return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
    }
    // 通過clazz來判斷glide要加載什么類型的圖片
    public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
        if (GlideDrawable.class.isAssignableFrom(clazz)) {
            return (Target<Z>) new GlideDrawableImageViewTarget(view);
        } else if (Bitmap.class.equals(clazz)) {
            return (Target<Z>) new BitmapImageViewTarget(view);
        } else if (Drawable.class.isAssignableFrom(clazz)) {
            return (Target<Z>) new DrawableImageViewTarget(view);
        } else {
            throw new IllegalArgumentException("Unhandled class: " + clazz
                    + ", try .as*(Class).transcode(ResourceTranscoder)");
        }
    }
public interface Target<R> extends LifecycleListener {

    int SIZE_ORIGINAL = Integer.MIN_VALUE;

    void onLoadStarted(Drawable placeholder);

    void onLoadFailed(Exception e, Drawable errorDrawable);

    void onResourceReady(R resource, GlideAnimation<? super R> glideAnimation);

    void onLoadCleared(Drawable placeholder);

    void getSize(SizeReadyCallback cb);

    void setRequest(Request request);
  
    Request getRequest();
}

上面是target的接口定義分扎,下面看一個具體實(shí)現(xiàn)

public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {

    public ImageViewTarget(ImageView view) {
        super(view);
    }


    @Override
    public Drawable getCurrentDrawable() {
        return view.getDrawable();
    }

    @Override
    public void setDrawable(Drawable drawable) {
        view.setImageDrawable(drawable);
    }

    @Override
    public void onLoadStarted(Drawable placeholder) {
        view.setImageDrawable(placeholder);
    }

    @Override
    public void onLoadFailed(Exception e, Drawable errorDrawable) {
        view.setImageDrawable(errorDrawable);
    }

    @Override
    public void onLoadCleared(Drawable placeholder) {
        view.setImageDrawable(placeholder);
    }

    @Override
    public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {
        if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
            setResource(resource);
        }
    }

    protected abstract void setResource(Z resource);

}

2项阴、創(chuàng)建request

    public <Y extends Target<TranscodeType>> Y into(Y target) {
        // 如果有就的request先刪除
        Request previous = target.getRequest();
        if (previous != null) {
            previous.clear();
            requestTracker.removeRequest(previous);
            previous.recycle();
        }
        // 創(chuàng)建新的request
        Request request = buildRequest(target);
        // 內(nèi)部會調(diào)用view的settag防止view復(fù)用時圖片錯位
        target.setRequest(request);
        lifecycle.addListener(target);
        // 交給request跟蹤器做request處理
        requestTracker.runRequest(request);

        return target;
    }

看一下buildRequest方法中怎么去創(chuàng)建request的

   private Request buildRequest(Target<TranscodeType> target) {
        if (priority == null) {
            priority = Priority.NORMAL;
        }
        return buildRequestRecursive(target, null);
    }

    private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
        if (thumbnailRequestBuilder != null) {
            ······
        //縮略圖相關(guān)設(shè)置
        } else {
            return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
        }
    }
    private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
            RequestCoordinator requestCoordinator) {
        return GenericRequest.obtain(
                loadProvider,
                model,
                signature,
                context,
                priority,
                target,
                ......);
    }
 public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
            LoadProvider<A, T, Z, R> loadProvider,
            A model,
            Key signature,
            Context context,
            ......) {
        //從隊(duì)列中取出一個request復(fù)用
        GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
        if (request == null) {
            request = new GenericRequest<A, T, Z, R>();
        }
        request.init(loadProvider,
                model,
                signature,
                context,
                priority,
                ......);
        return request;
    }

3、發(fā)起request請求

request是由RequestTracker負(fù)責(zé)管理的

public class RequestTracker {
    private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
   private final List<Request> pendingRequests = new ArrayList<Request>();
    public void runRequest(Request request) {
        requests.add(request);
        if (!isPaused) {
            request.begin();
        } else {
            pendingRequests.add(request);
        }
    }
}
    public void begin() {
        startTime = LogTime.getLogTime();
        if (model == null) {
            onException(null);
            return;
        }

        status = Status.WAITING_FOR_SIZE;
        // 有沒有通過override指定圖片尺寸
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            onSizeReady(overrideWidth, overrideHeight);
        } else {
            // 獲取target的尺寸笆包,獲取到后內(nèi)部會調(diào)用onSizeReady
            target.getSize(this);
        }

        if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
            // 開始加載設(shè)置占位圖
            target.onLoadStarted(getPlaceholderDrawable());
        }
    }

onSizeReady 開始加載

    @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和DataFetcher負(fù)責(zé)加載不同類型的數(shù)據(jù)
        ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
        final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);

        if (dataFetcher == null) {
            return;
        }
        // 對原始數(shù)據(jù)進(jìn)行解碼的類
        ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
       
        loadedFromMemoryCache = true;
        loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                priority, isMemoryCacheable, diskCacheStrategy, this);
        loadedFromMemoryCache = resource != null;
    
    }

ModelLoader:用于將任意復(fù)雜數(shù)據(jù)模型轉(zhuǎn)換DataFetcher可用的具體數(shù)據(jù)類型

public interface ModelLoader<T, Y> {
    DataFetcher<Y> getResourceFetcher(T model, int width, int height);
}

public class HttpUrlGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
    @Override
    public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
        // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time spent parsing urls.
        GlideUrl url = model;
        if (modelCache != null) {
            url = modelCache.get(model, 0, 0);
            if (url == null) {
                modelCache.put(model, 0, 0, model);
                url = model;
            }
        }
        return new HttpUrlFetcher(url);
    }
}

DataFetcher:加載資源的數(shù)據(jù)接口

public interface DataFetcher<T> {
    T loadData(Priority priority) throws Exception;
}
public class HttpUrlFetcher implements DataFetcher<InputStream> {
 @Override
    public InputStream loadData(Priority priority) throws Exception {
        return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
    }

    private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
            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.
            }
        }
        urlConnection = connectionFactory.build(url);
        for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
          urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
        }
        urlConnection.setConnectTimeout(2500);
        urlConnection.setReadTimeout(2500);
        urlConnection.setUseCaches(false);
        urlConnection.setDoInput(true);

        // Connect explicitly to avoid errors in decoders if connection fails.
        urlConnection.connect();
        if (isCancelled) {
            return null;
        }
        final int statusCode = urlConnection.getResponseCode();
        if (statusCode / 100 == 2) {
            return getStreamForSuccessfulRequest(urlConnection);
        } else if (statusCode / 100 == 3) {
            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 + 1, url, headers);
        } else {
            if (statusCode == -1) {
                throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
            }
            throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
        }
    }
}

4环揽、engine.load完成圖片加載

engine:異步處理總調(diào)度器。EnginJob負(fù)責(zé)線程管理庵佣,EngineRunnable是一個異步處理線程歉胶。DecodeJob是真正線程里獲取和處理圖片的地方。

    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();
        // 獲取加載圖片的唯一標(biāo)示
        final String id = fetcher.getId();
         //緩存中的key
        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
                loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
                transcoder, loadProvider.getSourceEncoder());
        // 從內(nèi)存緩存中獲取圖片
        EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
        if (cached != null) {
            cb.onResourceReady(cached);
            return null;
        }

        EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
        if (active != null) {
            cb.onResourceReady(active);
            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);
        }
        // 新建一個job從磁盤或網(wǎng)絡(luò)獲取
        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);

        return new LoadStatus(cb, engineJob);
    }

五巴粪、緩存

1通今、內(nèi)存緩存

  1. LruCache:保存已經(jīng)不再使用的圖片
    private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
        if (!isMemoryCacheable) {
            return null;
        }
        EngineResource<?> cached = getEngineResourceFromCache(key);
        if (cached != null) {
            cached.acquire();
            //放到正在使用的緩存中
            activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
        }
        return cached;
    }

    private EngineResource<?> getEngineResourceFromCache(Key key) {
        Resource<?> cached = cache.remove(key);

        final EngineResource result;
        if (cached == null) {
            result = null;
        } else if (cached instanceof EngineResource) {
            // Save an object allocation if we've cached an EngineResource (the typical case).
            result = (EngineResource) cached;
        } else {
            result = new EngineResource(cached, true /*isCacheable*/);
        }
        return result;
    }

public class LruResourceCache extends LruCache<Key, Resource<?>> implements MemoryCache {
    private ResourceRemovedListener listener;

    /**
     * Constructor for LruResourceCache.
     *
     * @param size The maximum size in bytes the in memory cache can use.
     */
    public LruResourceCache(int size) {
        super(size);
    }

    @Override
    public void setResourceRemovedListener(ResourceRemovedListener listener) {
        this.listener = listener;
    }

    @Override
    protected void onItemEvicted(Key key, Resource<?> item) {
        if (listener != null) {
            listener.onResourceRemoved(item);
        }
    }

    @Override
    protected int getSize(Resource<?> item) {
        return item.getSize();
    }

    @SuppressLint("InlinedApi")
    @Override
    public void trimMemory(int level) {
        if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
            // Nearing middle of list of cached background apps
            // Evict our entire bitmap cache
            clearMemory();
        } else if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Entering list of cached background apps
            // Evict oldest half of our bitmap cache
            trimToSize(getCurrentSize() / 2);
        }
    }
}
  1. 弱引用:保存正在使用的圖片
    private final Map<Key, WeakReference<EngineResource<?>>> activeResources;

   private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
        if (!isMemoryCacheable) {
            return null;
        }

        EngineResource<?> active = null;
        WeakReference<EngineResource<?>> activeRef = activeResources.get(key);
        if (activeRef != null) {
            active = activeRef.get();
            if (active != null) {
                active.acquire();
            } else {
                activeResources.remove(key);
            }
        }

        return active;
    }
  1. 內(nèi)存緩存寫入
class EngineJob{
    private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());

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

    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;
        //engineResource中有一個引用計(jì)數(shù)器,調(diào)用acquire加1
        engineResource.acquire();
        //在這里將引用寫入activeResources緩存
        listener.onEngineJobComplete(key, engineResource);

        for (ResourceCallback cb : cbs) {
            if (!isInIgnoredCallbacks(cb)) {
                engineResource.acquire();
                cb.onResourceReady(engineResource);
            }
        }
        // engineResource中有一個引用計(jì)數(shù)器肛根,調(diào)用release減1辫塌,變?yōu)?時放到lru緩存
        engineResource.release();
    }
}

2、磁盤緩存

入口位置是在EngineRunnable的run()方法派哲,run()方法中調(diào)用到decode()方法臼氨,decode()方法的源碼:

private Resource<?> decode() throws Exception {
    if (isDecodingFromCache()) {
        //從磁盤緩存讀取圖片
        return decodeFromCache();
    } else { 
        //從原始位置讀取圖片
        return decodeFromSource();
    }
}

來看一下decodeFromCache()方法的源碼,如下所示:

private Resource<?> decodeFromCache() throws Exception {
    Resource<?> result = null;
    try {
        //先嘗試讀取處理后的緩存圖
        result = decodeJob.decodeResultFromCache();
    } catch (Exception e) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Exception decoding result from cache: " + e);
        }
    }
    if (result == null) {
       //再嘗試讀取原圖的緩存圖
        result = decodeJob.decodeSourceFromCache();
    }
    return result;
}

處理后的緩存圖和原圖緩存圖對應(yīng)的是DiskCacheStrategy.RESULT和DiskCacheStrategy.SOURCE這兩個緩存模式芭届。
到DecodeJob具體看下這兩個讀取磁盤緩存的方法储矩,decodeResultFromCache()和decodeSourceFromCache():

public Resource<Z> decodeResultFromCache() throws Exception {
    if (!diskCacheStrategy.cacheResult()) {
        return null;
    }
    long startTime = LogTime.getLogTime();
    Resource<T> transformed = loadFromCache(resultKey);
    startTime = LogTime.getLogTime();
    Resource<Z> result = transcode(transformed);
    return result;
}

public Resource<Z> decodeSourceFromCache() throws Exception {
    if (!diskCacheStrategy.cacheSource()) {
        return null;
    }
    long startTime = LogTime.getLogTime();
    Resource<T> decoded = loadFromCache(resultKey.getOriginalKey());
    return transformEncodeAndTranscode(decoded);
}

兩個緩存方法都調(diào)用到了loadFromCache()方法,只是傳入的key不同褂乍。一個是處理后圖片的key持隧,一個是原始圖片的key。

private Resource<T> loadFromCache(Key key) throws IOException {
    File cacheFile = diskCacheProvider.getDiskCache().get(key);
    if (cacheFile == null) {
        return null;
    }
    Resource<T> result = null;
    try {
        result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
    } finally {
        if (result == null) {
            diskCacheProvider.getDiskCache().delete(key);
        }
    }
    return result;
}

那什么時候存入的呢?我們回到decodeFromSource()方法

public Resource<Z> decodeFromSource() throws Exception {
    Resource<T> decoded = decodeSource();
    return transformEncodeAndTranscode(decoded);
}
private Resource<T> decodeSource() throws Exception {
    Resource<T> decoded = null;
    try {
        long startTime = LogTime.getLogTime();
        //從網(wǎng)絡(luò)獲取圖片
        final A data = fetcher.loadData(priority);
        if (isCancelled) {
            return null;
        }
        decoded = decodeFromSourceData(data);
    } finally {
        fetcher.cleanup();
    }
    return decoded;
}

private Resource<T> decodeFromSourceData(A data) throws IOException {
    final Resource<T> decoded;
    //判斷是否設(shè)置了緩存原圖
    if (diskCacheStrategy.cacheSource()) {
        decoded = cacheAndDecodeSourceData(data);
    } else {
        long startTime = LogTime.getLogTime();
        decoded = loadProvider.getSourceDecoder().decode(data, width, height);
    }
    return decoded;
}

private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
    long startTime = LogTime.getLogTime();
    SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
    diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
    startTime = LogTime.getLogTime();
    Resource<T> result = loadFromCache(resultKey.getOriginalKey());
    return result;
}

decodeSource()方法中獲取圖片后逃片,調(diào)用到decodeFromSourceData()方法屡拨,然后判斷是否緩存原圖,是的話就調(diào)用到cacheAndDecodeSourceData(A data)方法褥实⊙嚼牵看進(jìn)去,還是調(diào)用了 diskCacheProvider.getDiskCache()獲取DiskLruCache工具類的實(shí)例性锭。然后調(diào)用put方法緩存了原圖赠潦。

到此我們緩存了原圖,處理后的圖片是什么時候緩存的草冈?肯定是在圖片處理之后她奥,在transformEncodeAndTranscode()方法中:

private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
    long startTime = LogTime.getLogTime();
    Resource<T> transformed = transform(decoded);
    writeTransformedToCache(transformed);
    startTime = LogTime.getLogTime();
    Resource<Z> result = transcode(transformed);
    return result;
}

private void writeTransformedToCache(Resource<T> transformed) {
    if (transformed == null || !diskCacheStrategy.cacheResult()) {
        return;
    }
    long startTime = LogTime.getLogTime();
    SourceWriter<Resource<T>> writer = new SourceWriter<Resource<T>>(loadProvider.getEncoder(), transformed);
    diskCacheProvider.getDiskCache().put(resultKey, writer);
}

transformEncodeAndTranscode中先對圖片進(jìn)行了轉(zhuǎn)換,然后調(diào)用writeTransformedToCache(transformed);判斷是否緩存處理后的圖片怎棱,是就對處理后的圖片進(jìn)行了緩存哩俭。調(diào)用的同樣是DiskLruCache實(shí)例的put()方法,不過這里用的緩存Key是resultKey拳恋。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凡资,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隙赁,老刑警劉巖垦藏,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伞访,居然都是意外死亡掂骏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門厚掷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弟灼,“玉大人,你說我怎么就攤上這事冒黑√锇螅” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵抡爹,是天一觀的道長掩驱。 經(jīng)常有香客問我,道長豁延,這世上最難降的妖魔是什么昙篙? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮诱咏,結(jié)果婚禮上苔可,老公的妹妹穿的比我還像新娘。我一直安慰自己袋狞,他們只是感情好焚辅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著苟鸯,像睡著了一般同蜻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上早处,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天湾蔓,我揣著相機(jī)與錄音,去河邊找鬼砌梆。 笑死默责,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的咸包。 我是一名探鬼主播桃序,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烂瘫!你這毒婦竟也來了媒熊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芦鳍,沒想到半個月后嚷往,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怜校,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年间影,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茄茁。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖巩割,靈堂內(nèi)的尸體忽然破棺而出裙顽,到底是詐尸還是另有隱情,我是刑警寧澤宣谈,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布愈犹,位于F島的核電站,受9級特大地震影響闻丑,放射性物質(zhì)發(fā)生泄漏漩怎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一嗦嗡、第九天 我趴在偏房一處隱蔽的房頂上張望勋锤。 院中可真熱鬧,春花似錦侥祭、人聲如沸叁执。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谈宛。三九已至,卻和暖如春胎署,著一層夾襖步出監(jiān)牢的瞬間吆录,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工琼牧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恢筝,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓障陶,卻偏偏與公主長得像滋恬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子抱究,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容