Android_Glide源码分析

本文详细剖析了Glide在Android中的源码实现,从基本使用到内部的生命周期管理,包括LinkedHashMap的数据结构和LruCache的工作原理。通过分析Glide如何在主线程中判断、Fragment的生命周期管理、Request的执行流程,以及数据缓存机制,揭示了Glide高效加载和管理图片的秘密。
摘要由CSDN通过智能技术生成

Android_Glide源码分析


本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.csdn.net/Rozol/article/details/73252999


Glide源码讲解

基本使用

Glide.with(this).load(url).into(imageview);

源码讲解

  1. 看下.with(this)做了什么

    public static RequestManager with(Context context) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(context);
    }
    
    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);
    }
    
    @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.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.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }
    
    @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) {
                current = new RequestManagerFragment();
                pendingRequestManagerFragments.put(fm, current);
                fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
            }
        }
        return current;
    }
    • 先调用Util.isOnMainThread()判断是否在主线程

      public static boolean isOnMainThread() {
          return Looper.myLooper() == Looper.getMainLooper();
      }
       - 判断是否在主线程,原来是通过判断是否是主线程的Looper来判断的
      
    • 先调用assertNotDestroyed(activity)断言Activity还没有Destroy, 然后调用activity.getFragmentManager()获得一个FragmentManager
    • 调用getRequestManagerFragment(fm)获得RequestManagerFragment, 这个其实是一个用于实现生命周期管理的Fragment, 通过Fragment的回调管理RequestManager

      public class RequestManagerFragment extends Fragment {
          @SuppressLint("ValidFragment")
          RequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
              this.lifecycle = lifecycle;
          }
      
          @Override
          public void onStart() {
              super.onStart();
              lifecycle.onStart();
          }
      
          @Override
          public void onStop() {
              super.onStop();
              lifecycle.onStop();
          }
      
          @Override
          public void onDestroy() {
              super.onDestroy();
              lifecycle.onDestroy();
          }
      }
      • 可见RequestManager实现了LifecycleListener

        public class RequestManager implements LifecycleListener {
            RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
                    RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
                this.context = context.getApplicationContext();
                this.lifecycle = lifecycle;
                this.treeNode = treeNode;
                this.requestTracker = requestTracker;
                this.glide = Glide.get(context);
                this.optionsApplier = new OptionsApplier();
        
                ConnectivityMonitor connectivityMonitor = factory.build(context,
                        new RequestManagerConnectivityListener(requestTracker));
        
                // If we're the application level request manager, we may be created on a background thread. In that case we
                // cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
                // ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
                if (Util.isOnBackgroundThread()) {
                    new Handler(Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            lifecycle.addListener(RequestManager.this);
                        }
                    });
                } else {
                    lifecycle.addListener(this);
                }
                lifecycle.addListener(connectivityMonitor);
            }
        
            @Override
            public void onStart() {
                // onStart might not be called because this object may be created after the fragment/activity's onStart method.
                resumeRequests();
            }
        
            @Override
            public void onStop() {
                pauseRequests();
            }
        
            @Override
            public void onDestroy() {
                requestTracker.clearRequests();
            }
        }
  2. 上面我们得到了RequestManager的对象,接着调用.load(url)

    public DrawableTypeRequest<String> load(String string) {
        return (DrawableTypeRequest<String>) fromString().load(string);
    }
    
    @Override
    public DrawableRequestBuilder<ModelType> load(ModelType model) {
        super.load(model);
        return this;
    }
    
    public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
        this.model = model;
        isModelSet = true;
        return this;
    }
    • 这个很简单,就是给GenericRequestBuilder初始化值, 并返回了DrawableRequestBuilder
  3. 接着看.into(imageview)

    @Override
    public Target<GlideDrawable> into(ImageView view) {
        return super.into(view);
    }
    
    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();
       }
    
    // ↓↓↓
       Request request = buildRequest(target);
       target.setRequest(request);
       lifecycle.addListener(target);
       requestTracker.runRequest(request);
    
       return target;
    }
    • Request previous = target.getRequest()获取就的Request,如果有就删除他, 然后(buildRequest(target))构建新的Request, 进行绑定与(requestTracker.runRequest(request))发起请求, 并返回Target
    • requestTracker.runRequest(request)是如何执行的呢?

      public class RequestTracker {
          private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
          private final List<Request> pendingRequests = new ArrayList<Request>();
          private boolean isPaused;
      
          public void runRequest(Request request) {
              requests.add(request); // ←←←
              if (!isPaused) {
                  request.begin(); // ←←←
              } else {
                  pendingRequests.add(request);
              }
          }
      }
      
      public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback, ResourceCallback {
          @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));
              }
          }
      
          @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;
              // ↓↓↓
              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));
              }
          }
      }
      • 调用’request.begin()’执行请求, 状态改为Status.WAITING_FOR_SIZE,并调用onSizeReady(overrideWidth, overrideHeight)将状态改为Status.RUNNING,计算了一个四舍五入的宽高,然后将engine.load()发起了请求
      • loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
        priority, isMemoryCacheable, diskCacheStrategy, this);
        里做了什么?

        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);
        }
    • EngineResource<?> cached = loadFromCache(key, isMemoryCacheable)他会先去缓存(内存缓存)里找资源

      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 static class ResourceWeakReference extends WeakReference<EngineResource<?>> {
          private final Key key;
      
          public ResourceWeakReference(Key key, EngineResource<?> r, ReferenceQueue<? super EngineResource<?>> q) {
              super(r, q);
              this.key = key;
          }
      }
      
      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 LruCache<T, Y> {
          private final LinkedHashMap<T, Y> cache = new LinkedHashMap<T, Y>(100, 0.75f, true);
          public Y remove(T key) {
              final Y value = cache.remove(key);
              if (value != null) {
                  currentSize -= getSize(value);
              }
              return value;
          }
      }
       - 如果`getEngineResourceFromCache(key)`找到资源,则该资源会被用`WeakReference`(弱引用)一层,然后添加到activeResources
       - 调用`Resource<?> cached = cache.remove(key)`获取的资源是从LruCache获取的
      
      • EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);找不到的话,在到Active里找资源

        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;
        }
        • 可见然后会看getEngineResourceFromCache(key)activeResources(弱引用资源)添加的资源还在吗?如果已经被回收了,就删除key,然后返回资源
      • EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable)如果内存和弱引用集合都没有就创建EngineJob, EngineJob有diskCacheService和sourceService两个线程池

        class EngineJob implements EngineRunnable.EngineRunnableManager {
            private final Key key;
            private final ExecutorService diskCacheService;
            private final ExecutorService sourceService;
        
            public EngineJob(Key key, ExecutorService diskCacheService, ExecutorService sourceService, boolean isCacheable,
                    EngineJobListener listener) {
                this(key, diskCacheService, sourceService, isCacheable, listener, DEFAULT_FACTORY);
            }
        
            public void start(EngineRunnable engineRunnable) {
                this.engineRunnable = engineRunnable;
                future = diskCacheService.submit(engineRunnable); // ←←←
            }
        }
        
        class EngineRunnable implements Runnable, Prioritized {
            @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); // ←←←
                }
            }
        
            private Resource<?> decode() throws Exception {
                if (isDecodingFromCache()) {
                    return decodeFromCache(); // ←←←
                } else {
                    return decodeFromSource(); // ←←←
                }
            }
        
            private boolean isDecodingFromCache() {
                return stage == Stage.CACHE;
            }
        
            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;
            }
        }
        • 会先result = decodeJob.decodeResultFromCache()从处理过的资源磁盘缓存找, 没有找到, 则result = decodeJob.decodeSourceFromCache()在从原图磁盘缓存找
        • 如果都没找到, 则执行onLoadFailed(exception)

          private void onLoadFailed(Exception e) {
              if (isDecodingFromCache()) {
                  stage = Stage.SOURCE;
                  manager.submitForSource(this);
              } else {
                  manager.onException(e);
              }
          }
          
          @Override
          public void submitForSource(EngineRunnable runnable) {
              future = sourceService.submit(runnable);
          }
          • 磁盘没有找到,只能去网络找, EngineRunnable被放入了sourceService线程池中并执行
          • 状态从Stage.CACHE变为了Stage.SOURCE, 于是decode()里执行decodeFromSource()

            class DecodeJob<A, T, Z> {
                private Resource<?> decodeFromSource() throws Exception {
                    return decodeJob.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();
                        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;
                }
            
                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;
                }
            
                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); // ←←←
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
                        logWithTimeAndKey("Wrote source to cache", startTime);
                    }
            
                    startTime = LogTime.getLogTime();
                    Resource<T> result = loadFromCache(resultKey.getOriginalKey());
                    if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) {
                        logWithTimeAndKey("Decoded source from cache", startTime);
                    }
                    return result;
                }
            
                private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
                    long startTime = LogTime.getLogTime();
                    Resource<T> transformed = transform(decoded); // ←←←
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
                        logWithTimeAndKey("Transformed resource from source", startTime);
                    }
            
                    writeTransformedToCache(transformed); // ←←←
            
                    startTime = LogTime.getLogTime();
                    Resource<Z> result = transcode(transformed); // ←←←
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
                        logWithTimeAndKey("Transcoded transformed from source", startTime);
                    }
                    return result;
                }
            }
            
            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());
                    }
                }
            }
            • 首先会执行Resource<T> decoded = decodeSource()进行获取数据,然后执行transformEncodeAndTranscode(decoded)进行处理数据:Resource<T> transformed = transform(decoded)剪裁,writeTransformedToCache(transformed)写入磁盘,Resource<Z> result = transcode(transformed)转码
            • decodeSource()里会执行final A data = fetcher.loadData(priority)来获取数据,然后执行decoded = decodeFromSourceData(data)来解析并保存数据
            • 通过查看fetcher.loadData(priority)代码,我们发现原来是用urlConnection发起的网络请求
            • 在看看decodeFromSourceData(data), 执行了decoded = cacheAndDecodeSourceData(data)将图片资源保存到磁盘
        • 在来看看onLoadComplete(resource);做了什么?

          private void onLoadComplete(Resource resource) {
              manager.onResourceReady(resource);
          }
          
          class EngineJob implements EngineRunnable.EngineRunnableManager {
              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(); // ←←←
              }
          }
          • 可见是用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(); // ←←←
                        } 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;
            
                // 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();
            }
            
            @SuppressWarnings("unchecked")
            @Override
            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 (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
                    releaseResource(resource);
                    onException(new Exception("Expected to receive an object of " + transcodeClass
                            + " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}"
                            + " inside Resource{" + resource + "}."
                            + (received != null ? "" : " "
                                + "To indicate failure return a null Resource object, "
                                + "rather than a Resource object containing null data.")
                    ));
                    return;
                }
            
                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();
            
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: "
                            + (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache);
                }
            }
            
            @Override
            public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {
                if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
                    setResource(resource); // ←←←
                }
            }
            
            @Override
            protected void setResource(Bitmap resource) {
                view.setImageBitmap(resource); // ←←←
            }
            • 可见主要是设置图片
  4. 整理后的流程图

其他

通过Fragment的生命周期实现自身的管理

  • XXX管理的代码

    package me.luzhuo.glidedemo.other.lifecycle;
    
    import android.content.Context;
    import android.os.Handler;
    import android.os.Looper;
    import android.util.Log;
    
    import me.luzhuo.glidedemo.other.lifecycle.inter.Lifecycle;
    import me.luzhuo.glidedemo.other.lifecycle.inter.LifecycleListener;
    
    public class Manager implements LifecycleListener {
        private final String TAG = Manager.class.getSimpleName();
        private final Context context;
        private final Lifecycle lifecycle;
    
        public Manager(Context context, final Lifecycle lifecycle) {
            this.context = context.getApplicationContext();
            this.lifecycle = lifecycle;
    
            if (!Utils.isOnMainThread()) {
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        lifecycle.addListener(Manager.this);
                    }
                });
            } else {
                lifecycle.addListener(this);
            }
        }
    
        public static Manager with(Context context) {
            ManagerRetriever retriever = ManagerRetriever.get();
            return retriever.get(context);
        }
    
        @Override
        public void onStart() {
            Log.e(TAG, "Manager 将开始工作");
        }
    
        @Override
        public void onStop() {
            Log.e(TAG, "Manager 将暂停工作");
        }
    
        @Override
        public void onDestroy() {
            Log.e(TAG, "Manager 将停止工作");
        }
    }
  • ManagerRetriever主要做的是构建Fragment,并绑定鉴定,这里的代码多,是因为传入Content做相应的Fragment生成和管理

    public class ManagerRetriever {
        Manager applicationManager;
        static final String FRAGMENT_TAG = "me.luzhuo.glidedemo";
        private static final ManagerRetriever INSTANCE = new ManagerRetriever();
    
        public static ManagerRetriever get() {
            return INSTANCE;
        }
    
        public Manager get(Context context) {
            if (context == null) {
                throw new IllegalArgumentException("You cannot start a load on a null Context");
            } else if (Utils.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 Manager get(FragmentActivity activity) {
            if (!Utils.isOnMainThread()) {
                return get(activity.getApplicationContext());
            } else {
                assertNotDestroyed(activity);
                FragmentManager fm = activity.getSupportFragmentManager();
                return fragmentGet(activity, fm);
            }
        }
    
        public Manager get(Fragment fragment) {
            if (fragment.getActivity() == null) {
                throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
            }
            if (!Utils.isOnMainThread()) {
                return get(fragment.getActivity().getApplicationContext());
            } else {
                FragmentManager fm = fragment.getChildFragmentManager();
                return fragmentGet(fragment.getActivity(), fm);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        public Manager get(Activity activity) {
            if (!Utils.isOnMainThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
                return get(activity.getApplicationContext());
            } else {
                assertNotDestroyed(activity);
                android.app.FragmentManager fm = activity.getFragmentManager();
                return fragmentGet2(activity, fm);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        private static void assertNotDestroyed(Activity activity) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
                throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
            }
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
        public Manager 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 (!Utils.isOnMainThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
                return get(fragment.getActivity().getApplicationContext());
            } else {
                android.app.FragmentManager fm = fragment.getChildFragmentManager();
                return fragmentGet2(fragment.getActivity(), fm);
            }
        }
    
        private Manager getApplicationManager(Context context) {
            // Either an application context or we're on a background thread.
            if (applicationManager == null) {
                synchronized (this) {
                    if (applicationManager == null) {
                        applicationManager = new Manager(context.getApplicationContext(), getLifecycle);
                    }
                }
            }
            return applicationManager;
        }
    
        Lifecycle getLifecycle = new Lifecycle() {
            @Override
            public void addListener(LifecycleListener listener) {
                listener.onStart();
            }
        };
    
        Manager fragmentGet(Context context, FragmentManager fm) {
            LifecycleFragment current = getManagerFragment(fm);
            Manager manager = current.getManager();
            if (manager == null) {
                manager = new Manager(context, current.getLifecycle());
                current.setManager(manager);
            }
            return manager;
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        Manager fragmentGet2(Context context, android.app.FragmentManager fm) {
            LifecycleFragment2 current = getManagerFragment2(fm);
            Manager manager = current.getManager();
            if (manager == null) {
                manager = new Manager(context, current.getLifecycle());
                current.setManager(manager);
            }
            return manager;
        }
    
        LifecycleFragment getManagerFragment(final FragmentManager fm) {
            LifecycleFragment current = (LifecycleFragment) fm.findFragmentByTag(FRAGMENT_TAG);
            if (current == null) {
                if (current == null) {
                    current = new LifecycleFragment();
                    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                }
            }
            return current;
        }
    
        LifecycleFragment2 getManagerFragment2(final android.app.FragmentManager fm) {
            LifecycleFragment2 current = (LifecycleFragment2) fm.findFragmentByTag(FRAGMENT_TAG);
            if (current == null) {
                if (current == null) {
                    current = new LifecycleFragment2();
                    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                }
            }
            return current;
        }
    }
  • Utils就一个isOnMainThread()方法,根据Looper判断是否是主线程

    public class Utils {
        public static boolean isOnMainThread() {
            return Looper.myLooper() == Looper.getMainLooper();
        }
    }
  • 有两个Fragment,由于代码一样,仅仅是Fragment的包的引用不同,这里就写一份吧

    package me.luzhuo.glidedemo.other.lifecycle.fragment;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.support.v4.app.Fragment;
    import android.util.Log;
    
    import me.luzhuo.glidedemo.other.lifecycle.Manager;
    import me.luzhuo.glidedemo.other.lifecycle.inter.LifecycleImpl;
    
    public class LifecycleFragment extends Fragment{
        private static final String TAG = LifecycleFragment.class.getSimpleName();
        private Manager manager;
        private final LifecycleImpl lifecycle;
    
    
        public LifecycleFragment() {
            this(new LifecycleImpl());
        }
    
        // For testing only.
        @SuppressLint("ValidFragment")
        public LifecycleFragment(LifecycleImpl lifecycle) {
            this.lifecycle = lifecycle;
        }
    
        public LifecycleImpl getLifecycle() {
            return lifecycle;
        }
    
        public void setManager(Manager manager) {
            this.manager = manager;
        }
    
        public Manager getManager() {
            return this.manager;
        }
    
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            Log.e(TAG, "onAttach");
        }
    
        @Override
        public void onDetach() {
            super.onDetach();
            Log.e(TAG, "onDetach");
        }
    
        @Override
        public void onStart() {
            super.onStart();
            Log.e(TAG, "onStart");
            lifecycle.onStart();
        }
    
        @Override
        public void onStop() {
            super.onStop();
            Log.e(TAG, "onStop");
            lifecycle.onStop();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.e(TAG, "onDestroy");
            lifecycle.onDestroy();
        }
    
        @Override
        public void onLowMemory() {
            Log.e(TAG, "onLowMemory");
            super.onLowMemory();
        }
    }
  • 接下来是定义的一些接口,和接口的实现

    public interface Lifecycle {
        void addListener(LifecycleListener listener);
    }
    
    
    public class LifecycleImpl implements Lifecycle {
        private final List<LifecycleListener> lifecycleListeners = new ArrayList();
        private boolean isStarted;
        private boolean isDestroyed;
    
        @Override
        public void addListener(LifecycleListener listener) {
            lifecycleListeners.add(listener);
    
            if (isDestroyed) {
                listener.onDestroy();
            } else if (isStarted) {
                listener.onStart();
            } else {
                listener.onStop();
            }
        }
    
        public void onStart() {
            isStarted = true;
            for (LifecycleListener lifecycleListener : lifecycleListeners) {
                lifecycleListener.onStart();
            }
        }
    
        public void onStop() {
            isStarted = false;
            for (LifecycleListener lifecycleListener : lifecycleListeners) {
                lifecycleListener.onStop();
            }
        }
    
        public void onDestroy() {
            isDestroyed = true;
            for (LifecycleListener lifecycleListener : lifecycleListeners) {
                lifecycleListener.onDestroy();
            }
        }
    }
    
    
    public interface LifecycleListener {
    
        void onStart();
    
        void onStop();
    
        void onDestroy();
    }
    • 用于测试的Activity
    public class LifecycleTestActivity extends AppCompatActivity {
        private static final String TAG = "Test";
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Manager.with(this);
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.e(TAG, "onStart");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.e(TAG, "onStop");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.e(TAG, "onDestroy");
        }
    }
  • 打印测试结果

LinkedHashMap的数据结构和算法

  • 首先看下该数据结构的构造方法

    public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {
        private transient LinkedHashMapEntry<K,V> header;
        private final boolean accessOrder;
    
        public LinkedHashMap(int initialCapacity,
                             float loadFactor,
                             boolean accessOrder) {
            super(initialCapacity, loadFactor);
            this.accessOrder = accessOrder;
        }
    
        @Override
        void init() {
            header = new LinkedHashMapEntry<>(-1, null, null, null);
            header.before = header.after = header;
        }
    }
    - 我们可以看到有一个`LinkedHashMapEntry<K,V> header`**头结点**,还有一个布尔类型的`accessOrder`用来控制是否按访问顺序排序
    
  • 看数据结构,当然必须先把结点理清楚

    private static class LinkedHashMapEntry<K,V> extends HashMapEntry<K,V> {
        // These fields comprise the doubly linked list used for iteration.
        LinkedHashMapEntry<K,V> before, after;
    
        LinkedHashMapEntry(int hash, K key, V value, HashMapEntry<K,V> next) {
            super(hash, key, value, next);
        }
    
        /**
         * Removes this entry from the linked list.
         */
        private void remove() {
            before.after = after;
            after.before = before;
        }
    
        /**
         * Inserts this entry before the specified existing entry in the list.
         */
        private void addBefore(LinkedHashMapEntry<K,V> existingEntry) {
            after  = existingEntry;
            before = existingEntry.before;
            before.after = this;
            after.before = this;
        }
    
        /**
         * This method is invoked by the superclass whenever the value
         * of a pre-existing entry is read by Map.get or modified by Map.set.
         * If the enclosing Map is access-ordered, it moves the entry
         * to the end of the list; otherwise, it does nothing.
         */
        void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
            if (lm.accessOrder) {
                lm.modCount++;
                remove();
                addBefore(lm.header);
            }
        }
    
        void recordRemoval(HashMap<K,V> m) {
            remove();
        }
    }
    • 从结点内内LinkedHashMapEntry<K,V> before, after可以看出这是一个双向循环的链式数据结构
    • 可见数据结构是这样的,接下来我们就来仔细分析下结点里的代码
    • remove()移除结点
    • addBefore()在指定结点前添加结点
    • recordAccess()在记录访问次数,lm.modCount++访问次数+1, 然后通过remove()删除结点,再将自己addBefore(lm.header)添加到头结点之前,也就是链表的末尾
    • recordRemoval()删除访问记录,只是简单的删除了结点
  • 链式的数据结构基本讲解的差不多了, 接下来简单的讲下 增删查

    • 增加

      void createEntry(int hash, K key, V value, int bucketIndex) {
          HashMapEntry<K,V> old = table[bucketIndex];
          LinkedHashMapEntry<K,V> e = new LinkedHashMapEntry<>(hash, key, value, old);
          table[bucketIndex] = e;
          e.addBefore(header);
          size++;
      }
      • 创建结点,创建后将结点添加到链表的末尾
    • public void clear() {
          super.clear();
          header.before = header.after = header;
      }
      • 将header结点的before和after指针都指向自己
    • 查(获取)

      public V get(Object key) {
          LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key);
          if (e == null)
              return null;
          e.recordAccess(this);
          return e.value;
      }
      • 根据key从hashmap中获取Entry,然后对该结点进行访问记录,返回其值

LruCache

  • 基本使用;

    • LruCache使用代码:

      import android.annotation.SuppressLint;
      import android.graphics.Bitmap;
      import android.os.Build;
      import android.support.v4.util.LruCache;
      import android.util.Log;
      
      public class ImageCache {
          // 使用最大可用内存值的1/5作为缓存的大小。
          private static final int MAXSIZE = (int) (Runtime.getRuntime().maxMemory() / 5);
      
          private static ImageCache cache = new ImageCache();
      
          public static ImageCache getInstance() {
              return cache;
          }
      
          // LruCache<标记, 图片>
          private LruCache<Object, Bitmap> lrucache;// 图片的缓存;设置的Value必须能够计算出所占有的内存的大小
      
          private ImageCache() {
              lrucache = new LruCache<Object, Bitmap>(MAXSIZE) {
      
                  @Override
                  protected int sizeOf(Object key, Bitmap value) {
                      System.out.println("内存已缓存:"+lrucache.size()+";总空间:"+MAXSIZE);
                      // size的变动代表该bitmap占用的内存大小
                      return getSize(value);
                  }
      
                  @Override
                  protected void entryRemoved(boolean evicted, Object key, Bitmap oldValue, Bitmap newValue) {
                      // evicted 为true表示MAXSIZE不够用
                      if (evicted) {
                          Log.d("memoryLruCache", "remove:" + key.toString());
                      }
                      super.entryRemoved(evicted, key, oldValue, newValue);
                  }
              };
          }
      
          /**
           * 获取图片占用内存的大小
           * @param value
           * @return
           */
          @SuppressLint("NewApi")
          private int getSize(Bitmap value) {
              // 如果当前版本 >= API12
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
                  return value.getByteCount();
              }
              return value.getRowBytes() * value.getHeight();
          }
      
          /**
           * 添加图片,如果添加的图片超过了设置的最大内存缓存,将清除一部分旧的图片
           * @param key
           * @param value
           */
          public void put(Object key, Bitmap value) {
              lrucache.put(key, value);
          }
      
          public Bitmap get(Object key) {
              Bitmap bitmap = lrucache.get(key);
              return bitmap;
          }
      
          /**
           * 清空所有缓存,包括内存和磁盘
           */
          public void clear() {
              lrucache.evictAll();
          }
      }
    • 测试代码:

      package me.luzhuo.lrucachedemo;
      
      import android.graphics.Bitmap;
      import android.graphics.BitmapFactory;
      import android.os.Environment;
      import android.support.v7.app.AppCompatActivity;
      import android.os.Bundle;
      import android.view.View;
      import android.view.ViewGroup;
      import android.widget.BaseAdapter;
      import android.widget.ImageView;
      import android.widget.ListView;
      import android.widget.TextView;
      
      import java.io.File;
      
      import me.luzhuo.lrucachedemo.utils.ImageCache;
      
      import static android.R.attr.bitmap;
      import static android.R.attr.key;
      
      public class MainActivity extends AppCompatActivity {
          private ListView listview;
          private int key;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              // 添加到内存缓存
              Bitmap bitmap = BitmapFactory.decodeFile(new File(Environment.getExternalStorageDirectory(),"abc.jpg").getPath());
      
              // hashcode的计算方法
              key = bitmap.hashCode();
              key = 31 * key + MainActivity.class.getSimpleName().hashCode();
      
              ImageCache.getInstance().put(key, bitmap);
      
              initView();
              initData();
          }
      
          private void initView() {
              listview = (ListView) findViewById(R.id.listView);
          }
      
          private void initData() {
              listview.setAdapter(new ImageAdapter());
          }
      
          class ImageAdapter extends BaseAdapter {
      
              @Override
              public int getCount() {
                  return 100;
              }
      
              @Override
              public Object getItem(int position) {
                  return null;
              }
      
              @Override
              public long getItemId(int position) {
                  return 0;
              }
      
              class ViewHodler{
                  TextView textview;
                  ImageView imageview;
              }
      
              @Override
              public View getView(int position, View convertView, ViewGroup parent) {
                  ViewHodler viewHodler;
                  if(convertView==null){
                      viewHodler = new ViewHodler();
                      convertView = View.inflate(MainActivity.this, R.layout.item, null);
                      viewHodler.textview = (TextView) convertView.findViewById(R.id.textview);
                      viewHodler.imageview = (ImageView) convertView.findViewById(R.id.imageview);
                      convertView.setTag(viewHodler);
                  }else{
                      viewHodler = (ViewHodler) convertView.getTag();
                  }
      
                  viewHodler.textview.setText("第"+position+"张");
                  // 从内存缓存获取数据
                  Bitmap bitmap = ImageCache.getInstance().get(key);
                  viewHodler.imageview.setImageBitmap(bitmap);
      
                  return convertView;
              }
      
          }
      }
  • 源码解析:

    1. 首先看下构造方法

      public class LruCache<K, V> {
          private final LinkedHashMap<K, V> map;
      
          /** Size of this cache in units. Not necessarily the number of elements. */
          private int size;
          private int maxSize;
      
          private int putCount;
          private int createCount;
          private int evictionCount;
          private int hitCount;
          private int missCount;
      
          /**
           * @param maxSize for caches that do not override {@link #sizeOf}, this is
           *     the maximum number of entries in the cache. For all other caches,
           *     this is the maximum sum of the sizes of the entries in this cache.
           */
          public LruCache(int maxSize) {
              if (maxSize <= 0) {
                  throw new IllegalArgumentException("maxSize <= 0");
              }
              this.maxSize = maxSize;
              this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
          }
      }
      • 我们可以得知,maxSize用于限制资源最大的可使用内存, 用LinkedHashMap<K, V> map来存储资源,并且要求LinkedHashMap访问记录
    2. 接着看下添加资源的方法

      public final V put(K key, V value) {
          if (key == null || value == null) {
              throw new NullPointerException("key == null || value == null");
          }
      
          V previous;
          synchronized (this) {
              putCount++;
              size += safeSizeOf(key, value);
              previous = map.put(key, value);
              if (previous != null) {
                  size -= safeSizeOf(key, previous);
              }
          }
      
          if (previous != null) {
              entryRemoved(false, key, previous, value);
          }
      
          trimToSize(maxSize);
          return previous;
      }
      • 可见添加资源时,会回调safeSizeOf(key, value)获取该资源的大小,然后加到size, 然后调用LinkedHashMap的put()方法添加资源,返回previous

        • 在LinkedHashMap中没有put()方法,看来是调用了HashMap的put()方法

          public V put(K key, V value) {
          
              // ...
          
              for (HashMapEntry<K,V> e = table[i]; e != null; e = e.next) {
                  Object k;
                  if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                      V oldValue = e.value;
                      e.value = value;
                      e.recordAccess(this);
                      return oldValue;
                  }
              }
          
              modCount++;
              addEntry(hash, key, value, i);
              return null;
          }
        • 调用HashMap的put(),如果这个key已经存在则返回旧元素,否则会调用addEntry()添加元素,然后返回null

          void addEntry(int hash, K key, V value, int bucketIndex) {
          
              // ...
          
              createEntry(hash, key, value, bucketIndex);
          }
        • 然后会调用LinkedHashMap中的createEntry()方法,因为LinkedHashMap重写了该方法,该方法创建了一个结点,并将其添加到链表末尾

      • 我们继续往下看,如果previous返回不为null,说明这个元素存在,调用了size -= safeSizeOf(key, previous),把加上的资源大小减掉

      • 然后会回调entryRemoved(false, key, previous, value)告知该资源没有添加到LruCache里,第一个boolean值表示该资源是否是因为超过限制而被移除,false表示不是,true表示是内存不足而删除.
      • 然后调用trimToSize(maxSize),我们看下做了什么

        public void trimToSize(int maxSize) {
            while (true) {
                K key;
                V value;
                synchronized (this) {
                    if (size < 0 || (map.isEmpty() && size != 0)) {
                        throw new IllegalStateException(getClass().getName()
                                + ".sizeOf() is reporting inconsistent results!");
                    }
        
                    if (size <= maxSize || map.isEmpty()) {
                        break;
                    }
        
                    Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
                    key = toEvict.getKey();
                    value = toEvict.getValue();
                    map.remove(key);
                    size -= safeSizeOf(key, value);
                    evictionCount++;
                }
        
                entryRemoved(true, key, value, null);
            }
        }
        • 可知原来是在判断添加数据后size是否超过了maxSize,如果超过了就删除元素,直到size <= maxSize || map.isEmpty()为止,删除数据是从LinkedHashMap第一个数据开始删的,因为被访问的元素都在链表末尾,第一个元素恰恰是最少被访问的
    3. 然后在看下获取资源的方法

      public final V get(K key) {
          if (key == null) {
              throw new NullPointerException("key == null");
          }
      
          V mapValue;
          synchronized (this) {
              mapValue = map.get(key);
              if (mapValue != null) {
                  hitCount++;
                  return mapValue;
              }
              missCount++;
          }
      
          // ...
      }
      • 就是调用LinkedHashMap的get()方法,该被访问的结点会被移到列表末尾
    4. 清空缓存

      public final void evictAll() {
          trimToSize(-1); // -1 will evict 0-sized elements
      }
      • 也很简单,就是调用trimToSize(maxSize)把数据全部删掉,trimToSize(maxSize)的源码上面2拷贝过了,不再重复拷贝一份
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值