资讯专栏INFORMATION COLUMN

Glide源码分析

youkede / 1361人阅读

摘要:版本问题如何实现与生命周期的绑定如何实现缓存如何实现图片压缩如何实现与生命周期的绑定创建将其与传入的生命周期绑定这样做的好处是当时,也会做相应操作,如停掉图片加载绑定首先无论传入的是什么,只要是在子线程中调用创建的与绑定,这样创建的的生命周

版本4.9.0

问题

Glide如何实现与生命周期的绑定?

Glide如何实现缓存?

Glide如何实现图片压缩?

Glide如何实现与生命周期的绑定?

创建RequestManger,将其与with()传入 Activity, Fragment的生命周期绑定,
这样做的好处是当Activity/Fragment stop/destroy时,RequestManager也会做相应操作,如停掉图片加载

绑定Application Context

首先无论with()传入的是什么,只要是在子线程中调用,创建的RequestManger与 Application Context绑定,这样创建的RequestMangager的生命周期与

    if (Util.isOnBackgroundThread()) {
        return get(fragment.getActivity().getApplicationContext());
     } else {
      ... ...
    }

这样做的目的是防止Activity,Fragment内存泄漏

Activity与FramgentActivity

    class RequestManagerFragment {
      ... ...
      private final ActivityFragmentLifecycle 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();
        unregisterFragmentWithRoot();
      }
      ... ...
    }
    class ActivityFragmentLifecycle implements Lifecycle {
      @Override
      public void addListener(@NonNull LifecycleListener listener) {
        lifecycleListeners.add(listener);

        if (isDestroyed) {
          listener.onDestroy();
        } else if (isStarted) {
          listener.onStart();
        } else {
          listener.onStop();
        }
      }
      void onStart() {
        isStarted = true;
        for (LifecycleListener lifecycleListener :             Util.getSnapshot(lifecycleListeners)) {
          lifecycleListener.onStart();
        }
      }

      void onStop() {
        isStarted = false;
        for (LifecycleListener lifecycleListener :     Util.getSnapshot(lifecycleListeners)) {
          lifecycleListener.onStop();
        }
      }

      void onDestroy() {
        isDestroyed = true;
        for (LifecycleListener lifecycleListener :     Util.getSnapshot(lifecycleListeners)) {
          lifecycleListener.onDestroy();
        }
      }
    }
    RequestManagerFragment current = getRequestManagerFragment(fm,         
                 parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager = factory.build(glide, current.getGlideLifecycle(),               current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }

RequestManagerFragment中创建了并对外提供ActivityFragmentLifecycle对象,
创建RequestManager时,传入ActivityFragmentLifecycle对象

    RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {

        ... ...      
        lifecycle.addListener(this); 
        ... ...
    }

    @Override
    public synchronized void onStart() {
      resumeRequests();
      targetTracker.onStart();
    }
    @Override
    public synchronized void onStop() {
      pauseRequests();
      targetTracker.onStop();
    }
    @Override
    public synchronized void onDestroy() {
      targetTracker.onDestroy();
      for (Target target : targetTracker.getAll()) {
        clear(target);
      }
      targetTracker.clear();
      requestTracker.clearRequests();
      lifecycle.removeListener(this);
      lifecycle.removeListener(connectivityMonitor);
      mainHandler.removeCallbacks(addSelfToLifecycle);
      glide.unregisterRequestManager(this);
    }

这样RequestManger.onStart(),onStop(),onDestroy()与Activity的生命周期通过Activity绑定的空Fragment实现了绑定

Fragment
与Activity的绑定方式类似,

    FragmentManager fm = fragment.getChildFragmentManager();

将RequestManger.onStart(),onStop(),onDestroy()与Fragment的生命周期通过Fragment绑定的空Fragment实现的绑定

View
通过View可以获取它所在的Activity 或 Fragment

   Activity activity = findActivity(view.getContext());

  @Nullable
  private Activity findActivity(@NonNull Context context) {
    if (context instanceof Activity) {
      return (Activity) context;
    } else if (context instanceof ContextWrapper) {
      return findActivity(((ContextWrapper) context).getBaseContext());
    } else {
      return null;
    }
  }
  
  @Nullable
  private Fragment findSupportFragment(@NonNull View target, @NonNull   
        FragmentActivity activity) {
        
    tempViewToSupportFragment.clear();
    findAllSupportFragmentsWithViews(
        activity.getSupportFragmentManager().getFragments(), tempViewToSupportFragment);
    Fragment result = null;
    View activityRoot = activity.findViewById(android.R.id.content);
    View current = target;
    while (!current.equals(activityRoot)) {
      result = tempViewToSupportFragment.get(current);
      if (result != null) {
        break;
      }
      if (current.getParent() instanceof View) {
        current = (View) current.getParent();
      } else {
        break;
      }
    }

    tempViewToSupportFragment.clear();
    return result;
  }

Context
通过Context获取Activity or FragmentActivity or Application Context

    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a   nullContext");
    } 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);

Glide如何实现缓存?

提供了两个内存缓存,分别存储强弱引用
弱引用的缓存: 存放正在使用的
强引用的缓存: 存放没有使用的

    Map activeEngineResources//在
    private final Map cache = new LinkedHashMap<>(100, 0.75f, true);//在LruCache类中

查找内存缓存,

1.先从弱引用的缓存查,
2.没有再从强引用的缓存查,查到后从强引用缓存中移除,加入到弱引用的缓存

Engine.load()方法

    EngineResource active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }
    EngineResource cached = loadFromCache(key, isMemoryCacheable);

Engine.loadFromCache()方法

  private EngineResource loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }

    EngineResource cached = getEngineResourceFromCache(key); //
    if (cached != null) {
      cached.acquire();
      activeResources.activate(key, cached);
    }
    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 /*isMemoryCacheable*/, true /*isRecyclable*/);
    }
    return result;
  }

Glide如何实现图片压缩?

Glide实现的等比压缩,保持原图长宽比例,主要是通过原图宽高和预设的宽高设置 BitmapFactory.Options.inSampleSize

    float widthPercentage = requestedWidth / (float) sourceWidth;
    float heightPercentage = requestedHeight / (float) sourceHeight;
    exactScaleFactor = Math.min(widthPercentage, heightPercentage);
    int outWidth = round(exactScaleFactor * sourceWidth);
    int outHeight = round(exactScaleFactor * sourceHeight);

    int widthScaleFactor = sourceWidth / outWidth;
    int heightScaleFactor = sourceHeight / outHeight;

    int scaleFactor = rounding == SampleSizeRounding.MEMORY
        ? Math.max(widthScaleFactor, heightScaleFactor)
        : Math.min(widthScaleFactor, heightScaleFactor);
    
    int powerOfTwoSampleSize;
    // BitmapFactory does not support downsampling wbmp files on platforms <= M. See b/27305903.
    if (Build.VERSION.SDK_INT <= 23
        && NO_DOWNSAMPLE_PRE_N_MIME_TYPES.contains(options.outMimeType)) {
      powerOfTwoSampleSize = 1;
    } else {
      powerOfTwoSampleSize = Math.max(1, Integer.highestOneBit(scaleFactor));
      if (rounding == SampleSizeRounding.MEMORY
          && powerOfTwoSampleSize < (1.f / exactScaleFactor)) {
        powerOfTwoSampleSize = powerOfTwoSampleSize << 1;
      }
    }
    options.inSampleSize = powerOfTwoSampleSize;

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73718.html

相关文章

  • Glide源码分析(一) Activity的生命周期与图片加载的关系

    摘要:从这段代码入手分析分析从这段代码可以看出无论传入的是还是或者干脆传入或都会调用这个方法而这个方法生成两个对象对象,并把它加到上对象这两个对象拥有共同的对象对象,当系统调用的生命周期,的生命周期随之被调用来处理列表,将的生命周期与的生命周期联 从这段代码入手分析Glide Glide.with(context) .load(url) .placehol...

    Kosmos 评论0 收藏0
  • Glide源码分析(三)

    Glide取消图片加载1.在任务刚开始时;2.在EngineJob中,Future.cancel(true)3.在加载完成,但没有加载到控件;RequestManager.java: public void pauseRequests() { Util.assertMainThread(); requestTracker.pauseRequests(); ...

    econi 评论0 收藏0

发表评论

0条评论

youkede

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<