Android框架之Glide框架的使用和源码分析

本文详细介绍了Android图片加载库Glide的特点,与Fresco的对比,以及Glide的基本使用方法,包括添加依赖、权限声明和图片展示。接着探讨了Glide的源码,分析了with方法的生命周期绑定、监听以及回调。最后,文章总结了Glide的相关面试题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考资料:Glide全面解析 面试提问之Glide

Glide源码

一、Glide与其他图片加载框架的对比

Glide:

  • 多种图片格式的缓存,适用于更多的内容表现形式(如Gif、WebP、缩略图、Video)
  • 生命周期集成(根据Activity或者Fragment的生命周期管理图片加载请求)
  • 高效处理Bitmap(bitmap的复用和主动回收,减少系统回收压力)
  • 高效的缓存策略,灵活(Picasso只会缓存原始尺寸的图片,Glide缓存的是多种规格),
  • 加载速度快且内存开销小(默认Bitmap格式的不同,使得内存开销是Picasso的一半)

Fresco:

  • 最大的优势在于5.0以下(最低2.3)的bitmap加载。在5.0以下系统,Fresco将图片放到一个特别的内存区域(Ashmem区)
  • 大大减少OOM(在更底层的Native层对OOM进行处理,图片将不再占用App的内存)
  • 适用于需要高性能加载大量图片的场景

对于一般App来说,Glide完全够用,而对于图片需求比较大的App,为了防止加载大量图片导致OOM,Fresco 会更合适一些。并不是说用Glide会导致OOM,Glide默认用的内存缓存是LruCache,内存不会一直往上涨。

二、Glide的基本使用

1、添加依赖

api 'com.github.bumptech.glide:glide:4.11.0'

2、AndroidManifest.xml中声明网络权限

<uses-permission android:name="android.permission.INTERNET" />

3、展示图片的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/iv_glide_demo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"/>
</LinearLayout>

4、代码处理展示图片

public class GlideDemoActivity extends AppCompatActivity {
    @BindView(R.id.iv_glide_demo)
    ImageView ivGlideDemo;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo_glide);
        ButterKnife.bind(this);

        String url = "http://cn.bing.com/az/hprichbg/rb/Dongdaemun_ZH-CN10736487148_1920x1080.jpg";
        Glide.with(this)
                .load(url)
                .into(ivGlideDemo);
    }
}

以上是最基础的用法,也就是关键的三步走:先with(),再load(),最后into()。
这一行代码,包括加载网络上的图片、加载手机本地的图片、加载应用资源中的图片等。

  • Glide.with()方法用于创建一个加载图片的实例。with()方法可以接收Context、Activity或者Fragment类型的参数。
  • 如果调用的地方既不在Activity中也不在Fragment中呢?也没关系,我们可以获取当前应用程序的ApplicationContext,传入到with()方法当中。

注意:
with()方法中传入的实例会决定Glide加载图片的生命周期,如果传入的是Activity或者Fragment的实例,那么当这个Activity或Fragment被销毁的时候,图片加载也会停止。
如果传入的是ApplicationContext,只有当应用程序被杀掉的时候,图片加载才会停止。

5、Glide的扩展内容

String url = "http://cn.bing.com/az/hprichbg/rb/Dongdaemun_ZH-CN10736487148_1920x1080.jpg";
String gifUrl ="http://p1.pstatp.com/large/166200019850062839d3";
Glide.with(this)
       .load(url)
       .placeholder(R.mipmap.pic_loading)// 占位符
       .diskCacheStrategy(DiskCacheStrategy.NONE)//禁用Glide的缓存功能 测试占位图功能的额外配置
       .error(R.mipmap.pic_failed)//异常占位图
       .override(200, 200)// 指定图片大小
       .into(ivGlideDemo);

三、源码分析

1、从上面的用法可知,Glide的基础用法就三个方法,即Glide三部曲(with、load、into)

方法名作用
with空白Fragment管理生命周期机制
load构建RequestBuilder对象
into运行队列,等待队列/活动缓存、内存缓存

2、with源码分析
首先,有一个结论要知道,Glide内部有一监听onDestroy自动回收,无需手动回收,那这是如何做到的呢?
这就是with方法的作用了,在对应Activity中创建了一个空白Fragment并可随时监听到Activity的生命周期状态并根据状态做对应处理,具体是如何监听处理的看源码分析。

Glide的with分析,可根据以下几大模块来循序渐进的分析:
——生命周期的作用域Application/Fragment/Activity
——生命周期的绑定
——生命周期的监听
——生命周期的回调

2.1 声明周期的作用域
首先,跟着Glide的源码走,with()方法的代码如下:
Glide.java

 @NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

以上with方法有多个重载函数,其中参数分别对应有以下几种:
在这里插入图片描述
其中getRetriever调用的却是同一个,只是后面的RequestManagerRetriever.get()的处理有区别

  @NonNull
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    // Context could be null for other reasons (ie the user passes in null), but in practice it will
    // only occur due to errors with the Fragment lifecycle.
    Preconditions.checkNotNull(
        context,
        "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
            + "returns null (which usually occurs when getActivity() is called before the Fragment "
            + "is attached or after the Fragment is destroyed).");
    return Glide.get(context).getRequestManagerRetriever();
  }

其中,Glide.get(context) 基于 DCL 单例

  @NonNull
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      GeneratedAppGlideModule annotationGeneratedModule =
          getAnnotationGeneratedGlideModules(context.getApplicationContext());
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context, annotationGeneratedModule);
        }
      }
    }
    return glide;
  }

由此可看出with(…) 方法的返回值是 RequestManager ,而真正创建的地方在RequestManagerRetriever#get(…) 中;
RequestManagerRetriever.java

@NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
    // 子线程走这里
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
 @NonNull
  public RequestManager get(@NonNull 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
          // Only unwrap a ContextWrapper if the baseContext has a non-null application context.
          // Context#createPackageContext may return a Context without an Application instance,
          // in which case a ContextWrapper may be used to attach one.
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    return getApplicationManager(context);
  }

with是很多函数的重载,以上是以Activity为作用域的源码,根据传入的参数不同,将对应于 Application Activity Fragment 的作用域,具体如下:
——子线程:作用域Application,无空白Fragment
——主线程:加一空白Fragment

传入参数作用域
viewActivity/Fragment
FragmentFragment
ActivityActivity
contextApplication

Activity/Fragment/FragmentActivity作用域属于一类 都是一样的 都会搞一个空白的Fragment去监听Activity/Fragment/FragmentActivity, Application作用域是另外一类,不会搞空白的Fragment去监听;

2.2 生命周期的绑定
上面生命周期作用域的get方法中Activity和Fragment域都会调用supportFragmentGet()方法来获得 RequestManager,就此展开分析:
RequestManagerRetriever.java

@NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
      // 从 FragmentManager 中获取 SupportRequestManagerFragment
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    //从该 Fragment 中获取 RequestManager
    RequestManager requestManager = current.getRequestManager();
    // 首次获取,则实例化 RequestManager
    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);
       // 设置 Fragment 对应的 RequestMananger
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

注意:这个方法必须在主线程执行,因为子线程不可能调用到这里来
getSupportRequestManagerFragment方法分析

  @NonNull
  private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
      // 尝试获取 FRAGMENT_TAG 对应的 Fragment
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
    // 尝试从临时记录中获取Fragment
      current = pendingSupportRequestManagerFragments.get(fm);
      // 实例化Fragment
      if (current == null) {
      // 创建对象
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        // 若父层可见则调用onStart()生命周期
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        // 临时记录映射关系
        pendingSupportRequestManagerFragments.put(fm, current);
        // 提交Fragment事务
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        // post消息——为了移除临时记录中的映射关系
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

以上代码分析中重点关心下面三点:
第一点:从 FragmentManager 中获取 SupportRequestManagerFragment;
第二点:从该 Fragment 中获取 RequestManager;
第三点:首次获取,则实例化 RequestManager,后续从同一个SupportRequestManagerFragment 中都获取的是这个 RequestManager;

整个的关键核心在 getSupportRequestManagerFragment函数:
第一步:尝试获取 FRAGMENT_TAG 对应的 Fragment
第二步:尝试从临时记录中获取 Fragment
第三步:实例化 Fragment
第一点: 创建对象
第二点:如果父层可见,则调用 onStart() 生命周期
第三点:临时记录映射关系
第四点:提交 Fragment 事务
第五点:post 一个消息
第六点:移除临时记录中的映射关系

问题:在提交Fragment 事务之前,为什么需要先保存记录?
———为了避免 SupportRequestManagerFragment 在一个作用域中重复创建。
因为 commitAllowingStateLoss() 是将事务 post 到消息队列中的,也就是说,事务是异步处理的,而不是同步处理的。假设没有临时保存记录,一旦在事务异步等待执行时调用了 Glide.with(…) ,就会在该作用域中重复创建 Fragment。

2.3 生命周期的监听
框架为每个Activity 和 Fragment 作用域创建了一个无UI的Fragment,现在来分析 Glide 如何监听这个无界面 Fragment 的生命周期
SupportRequestManagerFragment.java

  private final ActivityFragmentLifecycle lifecycle;
  private final RequestManagerTreeNode requestManagerTreeNode =
      new SupportFragmentRequestManagerTreeNode();
  private final Set<SupportRequestManagerFragment> childRequestManagerFragments = new HashSet<>();

  @Nullable private SupportRequestManagerFragment rootRequestManagerFragment;
  @Nullable private RequestManager requestManager;
  @Nullable private Fragment parentFragmentHint;

  public SupportRequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }

  @VisibleForTesting
  @SuppressLint("ValidFragment")
  public SupportRequestManagerFragment(@NonNull 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();
    unregisterFragmentWithRoot();
  }

RequesstManagerRetriver.java

  @NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
 // 实例化 RequestManager
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

// RequestManager 工厂接口
  public interface RequestManagerFactory {
    @NonNull
    RequestManager build(
        @NonNull Glide glide,
        @NonNull Lifecycle lifecycle,
        @NonNull RequestManagerTreeNode requestManagerTreeNode,
        @NonNull Context context);
  }
// 默认 RequestManager 工厂接口实现类
  private static final RequestManagerFactory DEFAULT_FACTORY =
      new RequestManagerFactory() {
        @NonNull
        @Override
        public RequestManager build(
            @NonNull Glide glide,
            @NonNull Lifecycle lifecycle,
            @NonNull RequestManagerTreeNode requestManagerTreeNode,
            @NonNull Context context) {
          return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
        }
      };

RequestManager.java

 RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.context = context;
	.....
    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
    // 添加监听
      lifecycle.addListener(this);
    }
	.......
  }
  @Override
  public synchronized void onDestroy() {
  ......
  // 移除监听
    lifecycle.removeListener(this);
    ......
  }

以上代码流程可知实例化 RequestManager 时需要一个 Lifecycle对象,这个对象是在无界面 Fragment 中创建的,当 Fragment 的生命周期变化时,就是通过这个Lifecycle 对象将事件分发到 RequestManager

2.4 生命周期的回调
当 RequestManager 收到生命周期回调后的处理如下:

public interface Lifecycle {
  void addListener(@NonNull LifecycleListener listener);
  void removeListener(@NonNull LifecycleListener listener);
}
public interface LifecycleListener {
  void onStart();
  void onStop();
  void onDestroy();
}

故RequestManager会implements LifecycleListener 接口并调用函数做相对应处理:

  @Override
  public synchronized void onStart() {
  // Activity/Fragment 可见时恢复请求
    resumeRequests();
    targetTracker.onStart();
  }

  @Override
  public synchronized void onStop() {
  // Activity/Fragment 不可见时暂停请求
    pauseRequests();
    targetTracker.onStop();
  }

  @Override
  public synchronized void onDestroy() {
  // Activity/Fragment 销毁时销毁请求
    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);
  }

3 Glide的load分析

4 Glide的into分析(重点)

四、Glide相关面试题汇总

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值