Android Glide 分析

 Glide最基本用法:

Glide.with(context).load(url).into(imageView);

首先看看into方法:

public <Y extends Target<TranscodeType>> Y into(Y target) {
    Util.assertMainThread();  // 要求在主线程中
          ………
    Request request = buildRequest(target);  //生成一个请求
    target.setRequest(request);  // 把request请求加入到target里面,后面会用到
    lifecycle.addListener(target);  // 请求加入到生命周期管理里面
    requestTracker.runRequest(request);  // 调度请求

    return target;
}


1,首先看看请求如何生成(buildRequest

buildRequest --> buildRequestRecursive --> obtainRequest (这里可以请求缩略图和全图) --> GenericRequest.obtain()
 
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain() {
    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();  //初始化请求
    return request;
}
 

2 请求调度requestTracker.runRequest(request)

 RequestTracker 类就是一个请求的管理追踪类,它的注释是A class for tracking, canceling, and restarting in progress, completed, and failed requests.
 
public void runRequest(Request request) {
  requests.add(request);  //把请求放入请求链表
    if (!isPaused) {
       request.begin();   //开始请求
    } else {
       pendingRequests.add(request);  //如果当前请求被挂起,放入挂起链表
    }
}

再看看开始请求request.begin(); 由上面分析我们知道我们生成的是GenericRequest请求,看看它的begin()
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); // 如果调用了 GenericRequestBuilder的override(width, height) 指定了指定的宽高,则走这里
    } else {
       target.getSize(this);  // 没有指定宽高,则走这里,会根据前面into(imageView)的imgeView的大小来取得图片的宽高
    }

    if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
       target.onLoadStarted(getPlaceholderDrawable());   //加载占位图
    }
  }

我们这里没指定图片的大小所以走target.getSize(this) 这里,我们这里是imageView,所以分析下ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
中:
    public void getSize(SizeReadyCallback cb) {
        sizeDeterminer.getSize(cb);
    }
再看看SizeDeterminer中的getSize(),SizeDeterminer是ViewTaget的一个内部类
  public void getSize(SizeReadyCallback cb) {
            int currentWidth = getViewWidthOrParam();
            int currentHeight = getViewHeightOrParam();  //取得View 的宽高
            if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
                cb.onSizeReady(currentWidth, currentHeight);  //如果有宽高了就调用了SizeReadyCallback的onSizeReady
            } else {
                // 如果获取的宽高不对,会注册监听获取
                if (layoutListener == null) {
                    final ViewTreeObserver observer = view.getViewTreeObserver();
                    layoutListener = new SizeDeterminerLayoutListener(this);
                    observer.addOnPreDrawListener(layoutListener);
                }
            }
        }

由前面我们分析知道
target.getSize(this);我们传入的的是GenericRequest类,而GenericRequest类是实现了SizeReadyCallback接口的,所以再确定好view的长宽后会回调onSizeReady(),跟前面手动指定了长宽一样调用到这里:
   public void onSizeReady(int width, int height) {
      
        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); //注意这里的model就是我们要显示图片的Url,根据Url和要显示的长宽,生成一个dataFetcher类

        ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
     
        loadedFromMemoryCache = true;
        loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                priority, isMemoryCacheable, diskCacheStrategy, this); // 加载图片
     
    }
加载图片是由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 key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
                loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
                transcoder, loadProvider.getSourceEncoder()); //生成唯一的Key值

        cached = loadFromCache(key, isMemoryCacheable); //从内存中获取Bitmap
        if (cached != null) {
            cb.onResourceReady(cached); //如果内存中有,就回调显示
            return null;
        }

       active = loadFromActiveResources(key, isMemoryCacheable); //从活跃的内存缓存中获取bitmap
        if (active != null) {
             cb.onResourceReady(active); //如果内存中有,就回调显示
             return null;
        }

        EngineJob current = jobs.get(key); //如果内存缓存中没有,则判断EngineJob 列表中有没有当前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); //新建一个EngineJob
        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); // 新建一个EngineRunnable
        jobs.put(key, engineJob); 
        engineJob.addCallback(cb);  //把GenericRequest请求加入到engineJob里面,这里其实就是后面获取到bitmap后,会回调GenericRequest类的回调方法
        engineJob.start(runnable); //把runnable加入到engineJob,提交到线程池执行
        return new LoadStatus(cb, engineJob);
    }

分析Engine累我们知道这里面有两个cahe缓存bitmap资源 一个MemoryCache cache成员,一个 Map<Key, WeakReference<EngineResource<?>>> activeResources会先从loadFromCahe()取出bitmap后,把它加入到activeResource里面,对于没有缓存的bitmap会新建一个EngineJob和一个EngineRunnable,然后enjneJob在start()里面把EngineRunnable 提交到线程池执行。
enjneJob的start()
    public void start(EngineRunnable engineRunnable) {
        this.engineRunnable = engineRunnable;
        future = diskCacheService.submit(engineRunnable); 
    }
其中diskCacheService是一个ExecutorService线程池,提交到里面就会执行run方法,注意这里,返回的future是一个Future接口,在java多线程编程中常用,本地地址和网络地址开始都走这里
我们再看看EngineRunnable里面的run方法:
  @Override
    public void run() {
        if (isCancelled) {
            return;
        }

        Exception exception = null;
        Resource<?> resource = null;
        try {
            resource = decode();
        } catch (Exception e) {
       
        }

        if (resource == null) {
            onLoadFailed(exception);
        } else {
            onLoadComplete(resource);
        }
    }

再看看如何decode
    private Resource<?> decode() throws Exception {
        if (isDecodingFromCache()) {
            return decodeFromCache(); //默认先从Cahe中取bitmap,包括本地路径,
        } else {
            return decodeFromSource(); //从网络上获取
        }
    }

decodeFromCache
    private Resource<?> decodeFromCache() throws Exception {
        Resource<?> result = null;
        try {
            result = decodeJob.decodeResultFromCache(); //根据调用时缓存策略diskCacheStrategy(DiskCacheStrategy.RESULT)会走这里,这里会保存显示的中间尺寸

        } catch (Exception e) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "Exception decoding result from cache: " + e);
            }
        }

        if (result == null) {
            result = decodeJob.decodeSourceFromCache(); //根据调用时缓存策略diskCacheStrategy(DiskCacheStrategy.SOURCE)会走这里,这里只保存原图

        }
        return result;
    }

decodeSourceFromCache --> loadFromCache(resultKey.getOriginalKey()); 
    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);  //根据要显示的view的长宽处理缓存文件
        } finally {
            if (result == null) {
                diskCacheProvider.getDiskCache().delete(key);
            }
        }
        return result;
    }

如果硬盘上缓存了这个文件则decode成功,调用OnloadComplete(resource),返回给调用者,没有缓存这个文件就会返回null,会调用
EngineRunnable中的OnLoadFailed()
    private void onLoadFailed(Exception e) {
        if (isDecodingFromCache()) {
            stage = Stage.SOURCE;  //stage 变为SOURCE, 默认都是CAHE的,即默认从CAHE中取
            manager.submitForSource(this); //提交到Source 线程池
        } else {
            manager.onException(e);
        }
    }

EngineJob
    public void submitForSource(EngineRunnable runnable) {
        future = sourceService.submit(runnable);
    }

所以又回到了EngineRunnable中的Run() --> decode() 但是这次走的是 decodeFromSource() --> decodeJob.decodeFromSource();
    public Resource<Z> decodeFromSource() throws Exception {
        Resource<T> decoded = decodeSource();  //开始decode,可以得到bitmap
        return transformEncodeAndTranscode(decoded); //这里对bitmap进行处理,比如改变大小
    }

--> decodeSource
    private Resource<T> decodeSource() throws Exception {
        Resource<T> decoded = null;
        try {
            long startTime = LogTime.getLogTime();
            final A data = fetcher.loadData(priority);  //这里就是从网络上获取数据,proprity模式是normal
            if (isCancelled) {
                return null;
            }
            decoded = decodeFromSourceData(data);
        } finally {
            fetcher.cleanup();
        }
        return decoded;
    }

注意若是项目中有用到OKHTTP,fetcher.loadData会调用到OkHttpStreamFetcher里面的loadData()
  public InputStream loadData(Priority priority) throws Exception {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url.toStringUrl());

        for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
            String key = headerEntry.getKey();
            requestBuilder.addHeader(key, headerEntry.getValue()); //http 请求头部
        }

        Request request = requestBuilder.build(); //生成okhttp请求

        Response response = client.newCall(request).execute(); // 开始http 请求
        responseBody = response.body();  //返回结果
        if (!response.isSuccessful()) {
            throw new IOException("Request failed with code: " + response.code());
        }

        long contentLength = responseBody.contentLength(); //文件的长度
        stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength); // 得到文件流
        return stream;
    }

有了网络数据来源后再回到DecodeJob 里面进入decodeFromSourceData()方法
  private Resource<T> decodeFromSourceData(A data) throws IOException {
        final Resource<T> decoded;
        if (diskCacheStrategy.cacheSource()) { //根据缓存bitmap图大小的方式
            decoded = cacheAndDecodeSourceData(data); //得到缓存全尺寸图片
        } else {
            long startTime = LogTime.getLogTime();
            decoded = loadProvider.getSourceDecoder().decode(data, width, height);  //得到view相应大小图片
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Decoded from source", startTime);
            }
        }
        return decoded;
    }

--> caheAndDecodeSourceData(data)
    private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
     
        SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data); //构建一个写Disk的writer类
        diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer); //缓存写入进diskCahe 硬盘
      
        startTime = LogTime.getLogTime();
        Resource<T> result = loadFromCache(resultKey.getOriginalKey()); //再从diskCahe中取出来返回
       
        return result;
    }

所以从上面分析可知到glide是如何获取到的bitmap的,从网络上获取的也会先缓存到diskCahe中,这样再从diskCahe中取出来,据上面分析可知,从cahe中取bitmap时会根据要显示imageView的大小进行处理。下面再看看如何把获取到的bitmap传给用户
还是在EngineRunnable里面,的Run()方法里,再上面获取到Resource后,会调用onLoadComplete(resource
    private void onLoadComplete(Resource resource) {
        manager.onResourceReady(resource);
    }

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

其中:MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback()); 是一个Handler
    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(); //如果是取得bitmap
                } else {
                    job.handleExceptionOnMainThread();
                }
                return true;
            }

            return false;
        }
    }

-->
  private void handleResultOnMainThread() {
       
        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();
                cb.onResourceReady(engineResource);  //回调给用户
            }
        }
        // Our request is complete, so we can release the resource.
        engineResource.release();
    }

这里由前面我们生成EngineJob时把GenericRequest传了进来,所以这里回调GenericRequest的onResourceReady()fang
 public void onResourceReady(Resource<?> resource) {
        if (resource == null) {
            onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass
                    + " inside, but instead got null."));
            return;
        }

        Object received = resource.get();
       

        if (!canSetResource()) {
            releaseResource(resource);
            // We can't set the status to complete before asking canSetResource().
            status = Status.COMPLETE;
            return;
        }

        onResourceReady(resource, (R) received);
    }

-->
    private void onResourceReady(Resource<?> resource, R result) {
        // We must call isFirstReadyResource before setting status.
        boolean isFirstResource = isFirstReadyResource();
        status = Status.COMPLETE;
        this.resource = resource;

        if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
                isFirstResource)) {
            GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
            target.onResourceReady(result, animation); //传递结果出去
        }

        notifyLoadSuccess();
    }

自此glide一个流程已经跑完


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值