Glide生命周期管理

Glide生命周期管理

1.Glide特點(diǎn)
  • 使用簡單
  • 可配置度高假勿,自適應(yīng)程度高
  • 支持常見圖片格式(jpg、png态鳖、gif转培、webp)
  • 支持多種數(shù)據(jù)源(網(wǎng)絡(luò)、本地浆竭、資源浸须、Assets等)
  • 高效緩存策略(支持Memory和Disk圖片緩存惨寿,默認(rèn)Bitmap格式采用RGB_565內(nèi)存小)
  • 生命周期集成(根據(jù)Activity/Fragment生命周期自動(dòng)管理請求)
  • 高效處理Bitmap(使用BitmapPool復(fù)用Bitmap删窒,主動(dòng)調(diào)用recycle回收需要回收的Bitmap)
2.Glide使用攻略
Glide.with(this)
 //  .asBitmap()//只允許加載靜態(tài)圖片裂垦,若傳入gif圖會(huì)展示第一幀(要在load之前)
 //  .asGif()//指定gif格式(要在load之前)
 //  .asDrawable()//指定drawable格式(要在load之前)
     .load(imageUrl)//被加載圖像的url地址
     .placeholder(R.drawable.ic_placeholder)//占位圖片
     .error(R.drawable.ic_error)//錯(cuò)誤圖片
     .transition(GenericTransitionOptions.with(R.anim.zoom_in))//圖片動(dòng)畫
     .override(800,800)//設(shè)置加載尺寸
     .skipMemoryCache(true)//禁用內(nèi)存緩存功能
     .diskCacheStrategy(DiskCacheStrategy.NONE)//不緩存任何內(nèi)容
  // .diskCacheStrategy(DiskCacheStrategy.DATA)//只緩存原始圖片
  // .diskCacheStrategy(DiskCacheStrategy.RESOURCE)//只緩存轉(zhuǎn)換后的圖片
  // .diskCacheStrategy(DiskCacheStrategy.ALL)//緩存所有
  // .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)//Glide根據(jù)圖片資源智能地選擇使用哪一種緩存策略(默認(rèn))
     .listener(new RequestListener<Drawable>() {//監(jiān)聽圖片加載狀態(tài)
        //圖片加載完成
         @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肌索,F(xiàn)ragmentActivity蕉拢,F(xiàn)ragment和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企量,通過建造者模式創(chuàng)建了一個(gè)GlideBuilder對象(資源請求線程池,本地緩存加載線程池亡电,動(dòng)畫線程池届巩,內(nèi)存緩存器,磁盤緩存工具等等)份乒。

構(gòu)造完RequestManagerRetriever通過get返回一個(gè) RequestManager(以Activity為例)

//通過Activity拿到RequestManager
public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      //如果是子線程就用Application級別的context恕汇,也就是不進(jìn)行生命周期管理
      return get(activity.getApplicationContext());
    } else {
      //檢查Activity是否銷毀
      assertNotDestroyed(activity)
      //拿到當(dāng)前Activity的FragmentManager
      android.app.FragmentManager fm = activity.getFragmentManager();
      //生成一個(gè)Fragment去綁定一個(gè)請求管理RequestManager
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

如果當(dāng)前線程是子線程,則不需要對Glide生命周期進(jìn)行管理或辖,否則通過fragmentGet函數(shù)創(chuàng)建一個(gè)fragment:

 private RequestManager fragmentGet(@NonNull Context context,
     @NonNull android.app.FragmentManager fm,
     @Nullable android.app.Fragment parentHint,
     boolean isParentVisible) {
   //①在當(dāng)前Activity添加一個(gè)Fragment用于管理請求的生命周期
   RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
   //獲取RequestManager
   RequestManager requestManager = current.getRequestManager();
   //如果不存在RequestManager瘾英,則創(chuàng)建
   if (requestManager == null) {
     Glide glide = Glide.get(context);
     //②構(gòu)建RequestManager  
     //current.getGlideLifecycle()就是ActivityFragmentLifecycle,也就是構(gòu)建RequestManager時(shí)會(huì)傳入fragment中的ActivityFragmentLifecycle
     requestManager =
         factory.build(
             glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
     //將構(gòu)建出來的RequestManager綁定到fragment中
     current.setRequestManager(requestManager);
   }
   //返回當(dāng)前請求的管理者
   return requestManager;
 }

①Fragment與Activity的綁定—>getRequestManagerFragment:

private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    //通過TAG拿到已經(jīng)實(shí)例化過的fragment(也就是同一個(gè)Activity Glide.with多次颂暇,沒必要?jiǎng)?chuàng)建多個(gè)fragment)
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      //如果當(dāng)前Activity中沒有拿到管理生命周期的fragment缺谴,那就從緩存取
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        //如果緩存也沒有,直接new一個(gè)
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          //執(zhí)行請求
          current.getGlideLifecycle().onStart();
        }
        //添加到Map緩存中(防止fragment重復(fù)創(chuàng)建)
        pendingRequestManagerFragments.put(fm, current);
        //將fragment綁定到activity
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        //添加后發(fā)送清理緩存
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

②構(gòu)建RequestManager并設(shè)置監(jiān)聽

//此工廠就是為了構(gòu)建出 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) {
      //實(shí)例化一個(gè)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));
        
   //添加生命周期監(jiān)聽
    if (Util.isOnBackgroundThread()) {
      //子線程通過handler將當(dāng)前對象注冊到ActivityFragmentLifecycle
      mainHandler.post(addSelfToLifecycle);
    } else {
      //將當(dāng)前對象注冊到ActivityFragmentLifecycle
      lifecycle.addListener(this);
    }
    //添加網(wǎng)絡(luò)變化的監(jiān)聽
    lifecycle.addListener(connectivityMonitor);

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

    glide.registerRequestManager(this);
  }
  //...
    
  //RequestManager實(shí)現(xiàn)了fragment生命周期回調(diào)
  @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);
  }
      
}

構(gòu)建RequestManager的時(shí)候?qū)equestManager的生命周期與Fragment關(guān)聯(lián)起來了耳鸯。

Fragment是依附在Activity湿蛔,所以Activity的生命周期在Fragment中都有,接著我們來看下RequestManagerFragment:

public class RequestManagerFragment extends Fragment {
  //生命周期的關(guān)鍵就在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();
  }
  //...
}

生命周期的關(guān)鍵就在lifecycle县爬,F(xiàn)ragment生命周期變化時(shí)會(huì)主動(dòng)通知lifecycle執(zhí)行相應(yīng)方法阳啥。

接著看下ActivityFragmentLifecycle:

class ActivityFragmentLifecycle implements Lifecycle {
  //在Fragment生命周期變化時(shí)會(huì)通知所有的它的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();
    }
  }
}

這個(gè)ActivityFragmentLifecycle持有一個(gè)lifecycleListeners,在Fragment生命周期變化時(shí)會(huì)通知所有的它的Listener财喳。

4.Glide生命周期回調(diào)流程總結(jié)
glide生命周期.png

??Glide.with(this)綁定了Activity的生命周期察迟。在Activity內(nèi)新建了一個(gè)無UI的Fragment,這個(gè)Fragment持有一個(gè)Lifecycle耳高,通過Lifecycle在Fragment關(guān)鍵生命周期通知RequestManager進(jìn)行相關(guān)從操作扎瓶。在生命周期onStart時(shí)繼續(xù)加載,onStop時(shí)暫停加載泌枪,onDestory時(shí)停止加載任務(wù)和清除操作栗弟。

Glide為什么對Fragment做緩存?
//添加到Map緩存中(防止fragment重復(fù)創(chuàng)建)
pendingRequestManagerFragments.put(fm, current);
//將fragment綁定到activity
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//添加后發(fā)送清理緩存的消息
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();

一個(gè)場景:通過Glide加載兩張圖片并設(shè)置到兩個(gè)ImageView上工闺。

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

??執(zhí)行到getRequestManagerFragment這個(gè)方法時(shí)乍赫,會(huì)通過開啟事務(wù)的方式綁定fragment到activity,綁定操作最終是通過主線程的handler發(fā)送消息處理的陆蟆,Handler中的消息時(shí)按照順序執(zhí)行的雷厂。如果不把msg1構(gòu)建的RequestManagerFragment放到pendingRequestManagerFragments中,那么在執(zhí)行msg2的時(shí)候會(huì)重新創(chuàng)建一個(gè)重復(fù)的fragment并add叠殷。最后發(fā)消息清理緩存(避免內(nèi)存泄漏和減少內(nèi)存壓力)改鲫,因?yàn)橄⑹前凑枕樞驁?zhí)行的,執(zhí)行清理緩存的時(shí)候msg1和msg2已經(jīng)執(zhí)行完畢林束。

Glide如何監(jiān)聽網(wǎng)絡(luò)變化像棘?

在構(gòu)建RequestManager的時(shí)候通過lifecycle.addListener(connectivityMonitor);添加網(wǎng)絡(luò)變化的監(jiān)聽 ,F(xiàn)ragment生命周期的變化會(huì)通知到默認(rèn)實(shí)現(xiàn)類DefaultConnectivityMonitor中對應(yīng)的方法壶冒。在onStart中registerReceiver(注冊監(jiān)聽手機(jī)網(wǎng)絡(luò)變化的廣播)缕题, 在onStop中unregisterReceiver。有網(wǎng)絡(luò)重連后重啟請求胖腾。

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;
      //判斷網(wǎng)絡(luò)狀態(tài)
      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.
  }
}

回調(diào)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) {
          //網(wǎng)絡(luò)重連后重啟請求
          requestTracker.restartRequests();
        }
      }
    }
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末烟零,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子咸作,更是在濱河造成了極大的恐慌锨阿,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件记罚,死亡現(xiàn)場離奇詭異墅诡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)桐智,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門末早,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酵使,你說我怎么就攤上這事荐吉。” “怎么了口渔?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵样屠,是天一觀的道長。 經(jīng)常有香客問我缺脉,道長痪欲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任攻礼,我火速辦了婚禮业踢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘礁扮。我一直安慰自己知举,他們只是感情好瞬沦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著雇锡,像睡著了一般逛钻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锰提,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天曙痘,我揣著相機(jī)與錄音,去河邊找鬼立肘。 笑死边坤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谅年。 我是一名探鬼主播茧痒,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼踢故!你這毒婦竟也來了文黎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤殿较,失蹤者是張志新(化名)和其女友劉穎耸峭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淋纲,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡劳闹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洽瞬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片本涕。...
    茶點(diǎn)故事閱讀 39,688評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖伙窃,靈堂內(nèi)的尸體忽然破棺而出菩颖,到底是詐尸還是另有隱情,我是刑警寧澤为障,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布晦闰,位于F島的核電站,受9級特大地震影響鳍怨,放射性物質(zhì)發(fā)生泄漏呻右。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一鞋喇、第九天 我趴在偏房一處隱蔽的房頂上張望声滥。 院中可真熱鬧,春花似錦侦香、人聲如沸落塑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芜赌。三九已至仰挣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缠沈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工错蝴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留洲愤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓顷锰,卻偏偏與公主長得像柬赐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子官紫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 1.Glide的簡介Glide肛宋,一個(gè)被google所推薦的圖片加載庫,作者是bumptech束世。這個(gè)庫被廣泛運(yùn)用在g...
    lfg楓林閱讀 1,195評論 0 3
  • 本文是Glide源碼解析系列的第一篇酝陈,通過這篇文檔,將可以了解到: 1.Glide如何綁定Activity毁涉、Fra...
    他的大姨父閱讀 8,632評論 6 42
  • Glide 中運(yùn)用到的優(yōu)秀技術(shù)有很多值得我們深入學(xué)習(xí)沉帮,這篇文章就來介紹一下 Glide 的生命周期是如何與 Act...
  • Glide生命周期管理:1、Glide如何綁定Activity贫堰、Fragment生命周期2穆壕、Glide如何監(jiān)聽內(nèi)存...
    CrisPeng閱讀 479評論 0 2
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友其屏。感恩相遇喇勋!感恩不離不棄。 中午開了第一次的黨會(huì)偎行,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,562評論 0 11