Glide生命周期管理

Glide生命周期管理

1.Glide特点
  • 使用简单
  • 可配置度高,自适应程度高
  • 支持常见图片格式(jpg、png、gif、webp)
  • 支持多种数据源(网络、本地、资源、Assets等)
  • 高效缓存策略(支持Memory和Disk图片缓存,默认Bitmap格式采用RGB_565内存小)
  • 生命周期集成(根据Activity/Fragment生命周期自动管理请求)
  • 高效处理Bitmap(使用BitmapPool复用Bitmap,主动调用recycle回收需要回收的Bitmap)
2.Glide使用攻略
Glide.with(this)
 //  .asBitmap()//只允许加载静态图片,若传入gif图会展示第一帧(要在load之前)
 //  .asGif()//指定gif格式(要在load之前)
 //  .asDrawable()//指定drawable格式(要在load之前)
     .load(imageUrl)//被加载图像的url地址
     .placeholder(R.drawable.ic_placeholder)//占位图片
     .error(R.drawable.ic_error)//错误图片
     .transition(GenericTransitionOptions.with(R.anim.zoom_in))//图片动画
     .override(800,800)//设置加载尺寸
     .skipMemoryCache(true)//禁用内存缓存功能
     .diskCacheStrategy(DiskCacheStrategy.NONE)//不缓存任何内容
  // .diskCacheStrategy(DiskCacheStrategy.DATA)//只缓存原始图片
  // .diskCacheStrategy(DiskCacheStrategy.RESOURCE)//只缓存转换后的图片
  // .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存所有
  // .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)//Glide根据图片资源智能地选择使用哪一种缓存策略(默认)
     .listener(new RequestListener<Drawable>() {//监听图片加载状态
        //图片加载完成
         @Override
         public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
            return false;
         }
         //图片加载失败
         @Override
         public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
             return false;
         }
     })
    .into(imageView);//图片最终要展示的地方
3.Glide生命周期原理分析

Glide.with(this)

with方法可以接受Context,Activity,FragmentActivity,Fragment和View不同的类型。

private static volatile Glide glide;
public static Glide get(@NonNull Context context) {
    if (glide == null) {
        synchronized (Glide.class) {
            if (glide == null) {
                checkAndInitializeGlide(context);
            }
        }
    }
    return glide;
}

双重检测单例模式(DCL)保证Glide对象的唯一性,get方法里面初始化了Glide,通过建造者模式创建了一个GlideBuilder对象(资源请求线程池,本地缓存加载线程池,动画线程池,内存缓存器,磁盘缓存工具等等)。

构造完RequestManagerRetriever通过get返回一个 RequestManager(以Activity为例)

//通过Activity拿到RequestManager
public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      //如果是子线程就用Application级别的context,也就是不进行生命周期管理
      return get(activity.getApplicationContext());
    } else {
      //检查Activity是否销毁
      assertNotDestroyed(activity)
      //拿到当前Activity的FragmentManager
      android.app.FragmentManager fm = activity.getFragmentManager();
      //生成一个Fragment去绑定一个请求管理RequestManager
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

如果当前线程是子线程,则不需要对Glide生命周期进行管理,否则通过fragmentGet函数创建一个fragment:

 private RequestManager fragmentGet(@NonNull Context context,
     @NonNull android.app.FragmentManager fm,
     @Nullable android.app.Fragment parentHint,
     boolean isParentVisible) {
   //①在当前Activity添加一个Fragment用于管理请求的生命周期
   RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
   //获取RequestManager
   RequestManager requestManager = current.getRequestManager();
   //如果不存在RequestManager,则创建
   if (requestManager == null) {
     Glide glide = Glide.get(context);
     //②构建RequestManager  
     //current.getGlideLifecycle()就是ActivityFragmentLifecycle,也就是构建RequestManager时会传入fragment中的ActivityFragmentLifecycle
     requestManager =
         factory.build(
             glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
     //将构建出来的RequestManager绑定到fragment中
     current.setRequestManager(requestManager);
   }
   //返回当前请求的管理者
   return requestManager;
 }

①Fragment与Activity的绑定—>getRequestManagerFragment:

private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    //通过TAG拿到已经实例化过的fragment(也就是同一个Activity Glide.with多次,没必要创建多个fragment)
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      //如果当前Activity中没有拿到管理生命周期的fragment,那就从缓存取
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        //如果缓存也没有,直接new一个
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          //执行请求
          current.getGlideLifecycle().onStart();
        }
        //添加到Map缓存中(防止fragment重复创建)
        pendingRequestManagerFragments.put(fm, current);
        //将fragment绑定到activity
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        //添加后发送清理缓存
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

②构建RequestManager并设置监听

//此工厂就是为了构建出 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) {
      //实例化一个RequestManager
      return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
    }
  };
public class RequestManager implements LifecycleListener,
    ModelTypes<RequestBuilder<Drawable>> { 

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;

    connectivityMonitor =
        factory.build(
            context.getApplicationContext(),
            new RequestManagerConnectivityListener(requestTracker));
        
   //添加生命周期监听
    if (Util.isOnBackgroundThread()) {
      //子线程通过handler将当前对象注册到ActivityFragmentLifecycle
      mainHandler.post(addSelfToLifecycle);
    } else {
      //将当前对象注册到ActivityFragmentLifecycle
      lifecycle.addListener(this);
    }
    //添加网络变化的监听
    lifecycle.addListener(connectivityMonitor);

    defaultRequestListeners =
        new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

    glide.registerRequestManager(this);
  }
  //...
    
  //RequestManager实现了fragment生命周期回调
  @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);
  }
      
}

构建RequestManager的时候将RequestManager的生命周期与Fragment关联起来了。

Fragment是依附在Activity,所以Activity的生命周期在Fragment中都有,接着我们来看下RequestManagerFragment:

public class RequestManagerFragment extends Fragment {
  //生命周期的关键就在ActivityFragmentLifecycle
  private final ActivityFragmentLifecycle lifecycle;
  public RequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }

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

生命周期的关键就在lifecycle,Fragment生命周期变化时会主动通知lifecycle执行相应方法。

接着看下ActivityFragmentLifecycle:

class ActivityFragmentLifecycle implements Lifecycle {
  //在Fragment生命周期变化时会通知所有的它的Listener
  private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
  private boolean isStarted;
  private boolean isDestroyed;

  @Override
  public void addListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.add(listener);

    if (isDestroyed) {
      listener.onDestroy();
    } else if (isStarted) {
      listener.onStart();
    } else {
      listener.onStop();
    }
  }

  @Override
  public void removeListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.remove(listener);
  }

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

这个ActivityFragmentLifecycle持有一个lifecycleListeners,在Fragment生命周期变化时会通知所有的它的Listener。

4.Glide生命周期回调流程总结
glide生命周期.png

  Glide.with(this)绑定了Activity的生命周期。在Activity内新建了一个无UI的Fragment,这个Fragment持有一个Lifecycle,通过Lifecycle在Fragment关键生命周期通知RequestManager进行相关从操作。在生命周期onStart时继续加载,onStop时暂停加载,onDestory时停止加载任务和清除操作。

Glide为什么对Fragment做缓存?
//添加到Map缓存中(防止fragment重复创建)
pendingRequestManagerFragments.put(fm, current);
//将fragment绑定到activity
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//添加后发送清理缓存的消息
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();

一个场景:通过Glide加载两张图片并设置到两个ImageView上。

Glide.with(this).load(imageUrl1).into(imageView1);//msg1
Glide.with(this).load(imageUrl2).into(imageView2);//msg2
glide缓存fragment.png

  执行到getRequestManagerFragment这个方法时,会通过开启事务的方式绑定fragment到activity,绑定操作最终是通过主线程的handler发送消息处理的,Handler中的消息时按照顺序执行的。如果不把msg1构建的RequestManagerFragment放到pendingRequestManagerFragments中,那么在执行msg2的时候会重新创建一个重复的fragment并add。最后发消息清理缓存(避免内存泄漏和减少内存压力),因为消息是按照顺序执行的,执行清理缓存的时候msg1和msg2已经执行完毕。

Glide如何监听网络变化?

在构建RequestManager的时候通过lifecycle.addListener(connectivityMonitor);添加网络变化的监听 ,Fragment生命周期的变化会通知到默认实现类DefaultConnectivityMonitor中对应的方法。在onStart中registerReceiver(注册监听手机网络变化的广播), 在onStop中unregisterReceiver。有网络重连后重启请求。

final class DefaultConnectivityMonitor implements ConnectivityMonitor {
  private static final String TAG = "ConnectivityMonitor";
  private final Context context;
  @SuppressWarnings("WeakerAccess") @Synthetic final ConnectivityListener listener;

  @SuppressWarnings("WeakerAccess") @Synthetic boolean isConnected;
  private boolean isRegistered;

  private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(@NonNull Context context, Intent intent) {
      boolean wasConnected = isConnected;
      //判断网络状态
      isConnected = isConnected(context);
      if (wasConnected != isConnected) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "connectivity changed, isConnected: " + isConnected);
        }
            
        listener.onConnectivityChanged(isConnected);
      }
    }
  };

  DefaultConnectivityMonitor(@NonNull Context context, @NonNull ConnectivityListener listener) {
    this.context = context.getApplicationContext();
    this.listener = listener;
  }

  private void register() {
    if (isRegistered) {
      return;
    }

    // Initialize isConnected.
    isConnected = isConnected(context);
    try {
      // See #1405
      context.registerReceiver(connectivityReceiver,
          new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
      isRegistered = true;
    } catch (SecurityException e) {
      // See #1417, registering the receiver can throw SecurityException.
      if (Log.isLoggable(TAG, Log.WARN)) {
        Log.w(TAG, "Failed to register", e);
      }
    }
  }

  private void unregister() {
    if (!isRegistered) {
      return;
    }

    context.unregisterReceiver(connectivityReceiver);
    isRegistered = false;
  }

  @SuppressWarnings("WeakerAccess")
  @Synthetic
  // Permissions are checked in the factory instead.
  @SuppressLint("MissingPermission")
  boolean isConnected(@NonNull Context context) {
    ConnectivityManager connectivityManager =
        Preconditions.checkNotNull(
            (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
    NetworkInfo networkInfo;
    try {
      networkInfo = connectivityManager.getActiveNetworkInfo();
    } catch (RuntimeException e) {
     if (Log.isLoggable(TAG, Log.WARN)) {
        Log.w(TAG, "Failed to determine connectivity status when connectivity changed", e);
      }
      // Default to true;
      return true;
    }
    return networkInfo != null && networkInfo.isConnected();
  }

  @Override
  public void onStart() {
    register();
  }

  @Override
  public void onStop() {
    unregister();
  }

  @Override
  public void onDestroy() {
    // Do nothing.
  }
}

回调ConnectivityListener的onConnectivityChanged来处理请求

 private class RequestManagerConnectivityListener
      implements ConnectivityMonitor.ConnectivityListener {
    @GuardedBy("RequestManager.this")
    private final RequestTracker requestTracker;

    RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) {
      this.requestTracker = requestTracker;
    }

    @Override
    public void onConnectivityChanged(boolean isConnected) {
      if (isConnected) {
        synchronized (RequestManager.this) {
          //网络重连后重启请求
          requestTracker.restartRequests();
        }
      }
    }
  }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容