美文网首页 移动 前端 Python Android Java
Glide 图片库使用和原理(一)

Glide 图片库使用和原理(一)

作者: zcwfeng | 来源:发表于2020-12-31 19:00 被阅读0次

1 Glide 使用 ---4.11.0

导入库

implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

1.1 简单使用

class GlideTest : AppCompatActivity() {
    lateinit var binding: ActivityGlideTestBinding
    val imgUrl = "https://cn.bing.com/sa/simg/hpb/LaDigue_EN-CA1115245085_1920x1080.jpg"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_glide_test)
        binding.showImg.setOnClickListener {

            Glide.with(this).load(imgUrl).into(binding.contentImg)

        }
    }
}

1.2 其他部分用法

val doc1 = """
    Glide 加载图片的方式
    // 加载本地图片
    File file = new File(getExternalCacheDir() + "/image.jpg");
    Glide.with(this).load(file).into(imageView);

    // 加载应用资源
    int resource = R.drawable.image;
    Glide.with(this).load(resource).into(imageView);

    // 加载二进制流
    byte[] image = getImageBytes();
    Glide.with(this).load(image).into(imageView);

    // 加载Uri对象
    Uri imageUri = getImageUri();
    Glide.with(this).load(imageUri).into(imageView);
"""

val doc2 = """
    Glide 占位图,和一些属性实例
    Glide.with(this)
     .load(url)
     .asBitmap()
     .placeholder(R.drawable.loading)
     .error(R.drawable.error)
     .diskCacheStrategy(DiskCacheStrategy.NONE)
     .into(imageView);
     
    Glide.with(this).load(url)
     .asGif()
     .placeholder(R.drawable.loading).error(R.drawable.error).diskCacheStrategy(DiskCacheStrategy.NONE)
     .into(imageView);
     
    Glide.with(this).load(url).placeholder(R.drawable.loading.error(R.drawable.error).diskCacheStrategy(DiskCacheStrategy.NONE)
     .override(100, 100)
     .into(imageView);
"""

2 三部曲with,load,into

2.1

第一步

Glide#width(xxxx) 目标获取 RequestManager

第二步
Glide#load(xxx) 目标获取 RequestBuilder

第三步
Glide#into(xxx) 获取和处理Target

  1. 运行队列,等待队列
  2. 活动缓存
  3. 内存缓存
  4. 网络模型

2.1.1 with

监听Activity/Fragment生命周期

当我们的Fragment或Activity不可见的时候暂停请求,当我们的Fragment或Activity可见的时候回复请求

处理前台可见的 Activity / Fragment,提高资源利用率;
在有必要时释放资源以避免在应用在后台时被杀死,提高稳定性;

Glide#with(params)
with会有很多重载方法,params参数有这些种类:(FragmentActivity,androidx.fragment.app.Fragment,android.app.Fragment,View)
通过获取RequestManagerRetriever 进行检索

RequestManagerRetriever#get方法 多个重载

通过源码,我们会看到四个重载方法

public RequestManager get(@NonNull Context context)

public RequestManager get(@NonNull FragmentActivity activity)

public RequestManager get(@NonNull Fragment fragment)

public RequestManager get(@NonNull Activity activity)

public RequestManager get(@NonNull View view)

通过这些发放的分析,我们得出下面的分析

生命周期的作用域(1.Application, 2.Activity, 3.Fragment)
with 参数 作用域 代码中线程
Application 子线程使用with
View Fragment/Activity 主线程
Fragment Fragment 主线程
Activity Activity 主线程
FragmentActivity Activity 主线程
ServiceContext/ApplicationContext Application 主线程

一共分为两种:
第一种是作用域Application,它的生命周期是全局 的,不搞空白Fragment绑定Activity/Fragment
第二种是作用域非Application,它的生命周期是,专门搞空白Fragment绑定 Activity/Fragment

生成默认隐藏fragment ,我们发现有着几个方法

private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible)

private RequestManager fragmentGet(
      @NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible)


supportFragmentGet---->getSupportRequestManagerFragment
获取SupportRequestManagerFragment (Tag:FRAGMENT_TAG)的fragment

private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

fragmentGet---->getRequestManagerFragment
获取RequestManagerFragment (Tag:FRAGMENT_TAG)的fragment

private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }
生命周期的绑定

【记录保存】 FragmentManager -SupportRequestManagerFragment

RequestManagerRetriever .java

final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments =
new HashMap<>();

supportFragmentGet----getSupportRequestManagerFragment

  1. 从FragmentManager中获取SupportRequestManagerFragment
SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);

2.从该 Fragment 中获取 RequestManager

RequestManager requestManager =current.getRequestManager();

3.首次获取,则实例化 RequestManager

------> getSupportRequestManagerFragment
1.1 尝试获取 FRAGMENT_TAG 对应的 Fragment
1.2 尝试从临时记录中获取Fragment
如果为获取到
1.3 current==null---实例化 Fragment

1.3.1 创建对象SupportRequestManagerFragment
1.3.2 如果父层可见,则调用 onStart() 生命周期
1.3.3 临时记录映射关系pendingSupportRequestManagerFragments.put(fm, current)
1.3.4 提交 Fragment 事务
1.3.5 post 一个消息
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();

-》post 一个消息分析: RequestManagerRetriever 本身实现了Handler的callback
handleMessage中

case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
        FragmentManager supportFm = (FragmentManager) message.obj;
        key = supportFm;
        removed = pendingSupportRequestManagerFragments.remove(supportFm);
        break;

就是为了避免 SupportRequestManagerFragment 在一个作用域中重复创建。

因为 commitAllowingStateLoss() 是将事务 post 到消息队列中的,也就是说,事 务是异步处理的,而不是同步处理的。假设没有临时保存记录,一旦在事务异步等待 执行时调用了 Glide.with(...) ,就会在该作用域中重复创建 Fragment。

生命周期的监听机制

Glide内部会在 Activity/Fragment生命周期监听,网络变化监听,自动取消加 载或者重新加载

框架为每个Activity 和 Fragment 作用域创建了 一个无UI的Fragment

分析这个空Fragment---》 SupportRequestManagerFragment.java
看下我们比较关心的代码

ActivityFragmentLifecycle lifecycle

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

  
  public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }

 
  public void setRequestManager(@Nullable RequestManager requestManager) {
    this.requestManager = requestManager;
  }

 @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();
  }

回溯一下,RequestManagerRetriever.java 和 RequestManager.java

  1. 实例化RequestManager
Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
  1. RequestManager 工厂
public interface RequestManagerFactory {
    @NonNull
    RequestManager build(
        @NonNull Glide glide,
        @NonNull Lifecycle lifecycle,
        @NonNull RequestManagerTreeNode requestManagerTreeNode,
        @NonNull Context context);
  }
  1. 默认工厂接口实现
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 源码我们关心的部分

final Lifecycle lifecycle;

public RequestManager(
      @NonNull Glide glide,
      @NonNull Lifecycle lifecycle,
      @NonNull RequestManagerTreeNode treeNode,
      @NonNull Context context) {
......
    this.lifecycle = lifecycle;
    this.requestTracker = requestTracker;// 生命周期回调
。。。
if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {// 添加监听
      lifecycle.addListener(this);
    }
。。。

public synchronized void onDestroy() {
    targetTracker.onDestroy();
    ......
    lifecycle.removeListener(this);//remove 监听
  }
}

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

生命周期的回调

RequestsManger 收到的回调ConnectivityMonitor

public interface LifecycleListener {
    void onStart();
    void onStop();
    void onDestroy();
}

Activity/Fragment 不可见时暂停请求 (onStop() ) 函数 Activity/Fragment 可见时恢复请求 (onStart() ) 函数 Activity/Fragment 销毁时销毁请求 (onDestroy() )函数

---》 RequestManger 操作 requestTracker

@Override
  public synchronized void onStop() {
    pauseRequests();
    targetTracker.onStop();
  }

@Override
  public synchronized void onStart() {
    resumeRequests();
    targetTracker.onStart();
  }

  public synchronized void resumeRequests() {
    requestTracker.resumeRequests();
  }

public synchronized void pauseRequests() {
    requestTracker.pauseRequests();
  }

@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);
  }

相关文章

  • Glide 图片库使用和原理(一)

    1 Glide 使用 ---4.11.0 导入库 1.1 简单使用 1.2 其他部分用法 2 三部曲with,lo...

  • Glide知识点梳理

    Android常用图片库:Glide、Fresco图片库比较Fresco:Facebook出品,功能强大,使用较复...

  • Android基础(41)图片加载框架

    1)图片库对比2)Glide源码解析3)图片框架缓存实现4)LRUCache原理。LruCache默认缓存大小5)...

  • Glide 图片库原理(二)

    Glide 吐槽 源码太多了,状态机对于阅读源码来说是个苦力活,而且必须借助工具完成,推荐脑图 简化一个整个流程图...

  • Android知识点归纳---图片

    知识点归纳: 图片 图片库对比目前比较通用的图片库是Glide和Picasso库的大小和方法对比二者的jar包,G...

  • Android 图片库Glide - Glide3.x 官方wi

    简介Glide是一个Android图片库,确切地说应当叫『媒体框架』。支持图片、Gif、原生视频的加载。使用简单,...

  • Android图片库Glide使用

    Glide是谷歌推荐使用的android图片加载库。具有占用内存少、加载快、支持gif图片等优点。TX等大厂都在使...

  • Android 大厂面试(一)

    一、图片 参考答案: 1、图片库对比 Picasso Glide Fresco Picasso 毕加索 Squar...

  • Glide使用原理

    基础概念: Model:图片地址(网络url,本地文件,ResId等) Data:InputStream 根据图片...

  • Android常问的面试题(二)

    (一)图片 1、图片库对比 2、LRUCache原理 LruCache是个泛型类,主要原理是:把最近使用的对象用强...

网友评论

    本文标题:Glide 图片库使用和原理(一)

    本文链接:https://www.haomeiwen.com/subject/wdxhoktx.html