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);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章