Glide生命周期监听原理以及简单应用&利用空Fragment代理Activity

Glide关于生命周期监听的原理解析以及简单应用

在这里插入图片描述


相信大家都用过 Glide,Glide是一个快速高效的图片加载库,Glide提供了简单易用的API,可扩展的图片解码管道,以及自动的资源池技术。相信大家对它已经无比了解,我也不再赘述。详情大家可以看 Glide官网

本篇内容介绍的是Glide关于安全方面的内容——生命周期监听。

1.Glide生命周期监听原理

Glide作为一个图片加载工具,拥有非常强大的功能,其中一项能力就是对生命周期的监听。简单来说,在你的ImageView所在的fragment或者Activity被回收或主动退出后,Glide能够自动进行响应的处理,以防止内存泄露以及不必要的网络和性能的浪费。

1.1 从Glide初始化开始分析

话不多说,开始整篇,我们从Glide最常用的代码入手:

  	   Glide
  		  .with(this)
  		  .load(imageUrl)
          .placeholder(com.avatr.ivi.common.widget.R.drawable.ic_image_default)
          .error(com.avatr.ivi.common.widget.R.drawable.ic_image_default)
          .transform(transformation, new RoundedCorners(10))
          .into(image);

点进去看with方法


  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

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

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

  public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getContext()).get(fragment);
  }

  public static RequestManager with(@NonNull android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

  public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
  }

可以看到with有多个重载方法,但不管哪个方法,调用逻辑都是一样的,首先看看getRetriever(context:Context)


  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实例中获取RequestManagerRetriever,接着看Glide.get(context)


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

这段代码很简单,double check 初始化并返回Glide实例;

接着往下看checkAndInitializeGlide经过基层调用,最终到了下面


   private static void initializeGlide(
      @NonNull Context context,
      @NonNull GlideBuilder builder,
      @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
    Context applicationContext = context.getApplicationContext();
    List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
    

    //....省略部分代码.....


    Glide glide = builder.build(applicationContext);
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      try {
        module.registerComponents(applicationContext, glide, glide.registry);
      } catch (AbstractMethodError e) {
        throw new IllegalStateException(
            "Attempting to register a Glide v3 module. If you see this, you or one of your"
                + " dependencies may be including Glide v3 even though you're using Glide v4."
                + " You'll need to find and remove (or update) the offending dependency."
                + " The v3 module name is: "
                + module.getClass().getName(),
            e);
      }
    }
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
  }

重点是builder.build(applicationContext)


  Glide build(@NonNull Context context) {
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }

    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }

    if (animationExecutor == null) {
      animationExecutor = GlideExecutor.newAnimationExecutor();
    }

    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }

    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }

    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        bitmapPool = new LruBitmapPool(size);
      } else {
        bitmapPool = new BitmapPoolAdapter();
      }
    }

    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }

    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }

    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              animationExecutor,
              isActiveResourceRetentionAllowed);
    }

    if (defaultRequestListeners == null) {
      defaultRequestListeners = Collections.emptyList();
    } else {
      defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }

    GlideExperiments experiments = glideExperimentsBuilder.build();
    //这里,创建的RequestManagerRetriever
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory, experiments);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptionsFactory,
        defaultTransitionOptions,
        defaultRequestListeners,
        experiments);
  }

这里创建了Glide的一系列组件模块,然后调用构造函数传入。当然这里不是我们本章的终点,继续往下看RequestManagerRetriever.get()方法


  @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      frameWaiter.registerSelf(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

  @NonNull
  public RequestManager get(@NonNull Fragment fragment) {
    Preconditions.checkNotNull(
        fragment.getContext(),
        "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getContext().getApplicationContext());
    } else {
      // In some unusual cases, it's possible to have a Fragment not hosted by an activity. There's
      // not all that much we can do here. Most apps will be started with a standard activity. If
      // we manage not to register the first frame waiter for a while, the consequences are not
      // catastrophic, we'll just use some extra memory.
      if (fragment.getActivity() != null) {
        frameWaiter.registerSelf(fragment.getActivity());
      }
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getContext(), fm, fragment, fragment.isVisible());
    }
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else if (activity instanceof FragmentActivity) {
      return get((FragmentActivity) activity);
    } else {
      assertNotDestroyed(activity);
      frameWaiter.registerSelf(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull View view) {

  	//...省略部分代码及注释
    if (activity instanceof FragmentActivity) {
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      return fragment != null ? get(fragment) : get((FragmentActivity) activity);
    }

    // Standard Fragments.
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
  }

get()方法有多个多态方法,但到现在为止,我们常用的其实只有两个get(@NonNull FragmentActivity activity)get(@NonNull Fragment fragment),我们以前者为重点继续分析


  @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      frameWaiter.registerSelf(activity);
      //终点是这里
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

继续看supportFragmentGet:


  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    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);
      // This is a bit of hack, we're going to start the RequestManager, but not the
      // corresponding Lifecycle. It's safe to start the RequestManager, but starting the
      // Lifecycle might trigger memory leaks. See b/154405040
      if (isParentVisible) {
        requestManager.onStart();
      }
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

  private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
    // If we have a pending Fragment, we need to continue to use the pending Fragment. Otherwise
    // there's a race where an old Fragment could be added and retrieved here before our logic to
    // add our pending Fragment notices. That can then result in both the pending Fragmeng and the
    // old Fragment having requests running for them, which is impossible to safely unwind.
    SupportRequestManagerFragment current = pendingSupportRequestManagerFragments.get(fm);
    if (current == null) {
      current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

  • 首先,这段代码的意义很简单,构造一个SupportRequestManagerFragment类型的空的Fragment,注入当前Activity,并确保该Activity有且只有一个该类型Fragment(为什么只需要一个,以及如何保证只有一个,大家可以自行探索);
  • 然后,将GlideLifecycle实例注入到空Fragment;因为fragment会响应宿主activity的生命周期,这样就可以做到不侵入宿主(组件外部)activity的前提下监听其生命周期;进而在生命周期发生变化时,触发GlideLifecycle回调,控制GlideRequest工作状态。

1.2 原理总结

OK,Glide图片加载的任务如何关联生命周期的流程我们已经明白,这里再次总结一下:

  • 利用Fragment监听/代理Activity

fragment可以响应宿主activity的生命周期回调,并且会先回调fragment;
这样做有一个好处,当我们的代码作为SDK时,可以在不侵入使用者代码的情况下,达到对生命周期的监听

  • 空fragment只是宿主Activity的代理

fragment不仅可以响应activity的生命周期回调,而且可以响应其它例如onActivityResult,onConfigurationChangeonRequestPermissionsResult等等,同时,它还可以调用Activity的方法,例如startActivity,getResources()等其它方法

  • 何为空Fragment?

就是没有UI布局,不会显示出来的Fragment,它作为Activity的一部分,可以响应宿主Activity的所有生命周期以及其它的Activity回调;

2.简单应用

利用空Fragment代理Activity实际上有很多实用的应用场景,以下就简单举例两种

2.1 应用场景1-主题切换之昼夜模式变化监听



class ContextHelper private constructor() {
    private lateinit var mApp: Application
    private val mStack = Stack<Activity>()

    companion object {
        val INSTANCE: ContextHelper by lazy {
            ContextHelper()
        }
    }


    fun init(context: Context) {
        if (context is Activity) {
            mStack.add(context)
        }
        mApp = context.applicationContext as Application
        mApp.registerActivityLifecycleCallbacks(object : ActivityLifecycleAdapter() {
            override fun onActivityCreated(activity: Activity) {
                mStack.add(activity)
                notifyActivityChange(activity)
            }

            override fun onActivityDestroyed(activity: Activity) {
                super.onActivityDestroyed(activity)
                mStack.remove(activity)
                if (mStack.isNotEmpty()) {
                    notifyActivityChange(mStack.peek())
                } else {
                    notifyActivityChange(null)
                }
            }
        })
    }

    private fun notifyActivityChange(activity: Activity?) {
        for (each in mActivityChangeListeners) {
            each.onTopActivityChange(activity)
        }
    }

    private val mActivityChangeListeners = ArrayList<IOnTopActivityChangeListener>()

    fun addTopActivityChangeListener(listener: IOnTopActivityChangeListener) {
        mActivityChangeListeners.add(listener)
    }

    fun removeTopActivityChangeListener(listener: IOnTopActivityChangeListener) {
        mActivityChangeListeners.remove(listener)
    }

    /**
    * TopActivity 变化监听
    */
    interface IOnTopActivityChangeListener {
        fun onTopActivityChange(activity: Activity?)
    }

    public fun getTopActivity(): Activity? {
        try {
            return mStack.peek()
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }

    public fun getApp(): Application {
        return mApp
    }



abstract class ActivityLifecycleAdapter : ActivityLifecycleCallbacks {
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
        onActivityCreated(activity)
    }

    override fun onActivityStarted(activity: Activity) {
    }

    override fun onActivityResumed(activity: Activity) {
    }

    override fun onActivityPaused(activity: Activity) {
    }

    override fun onActivityStopped(activity: Activity) {
    }

    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
    }

    abstract fun onActivityCreated(activity: Activity)
    
}

基本道理大家都懂,就是在application注册ActivityLifecycleCallbacks,首先在Activity或者Application中初始化ContextHelper
这就获取到了TopActivity;

然后,在TopActivity中注入空Fragment


class AnySdkManager{


	fun init(context:Context){

		val topActivity = ContextHelper.INSTANCE.getTopActivity()
        topActivity?.let {
            addFragment(it)
        }
        ContextHelper.INSTANCE.addTopActivityChangeListener(object : IOnTopActivityChangeListener{
            override fun onTopActivityChange(activity: Activity?) {
                topActivity?.let {
		            addFragment(it)
		        }
            }

        })
	}

    private fun addFragment(activity: Activity) {
        val sfm = (activity as AppCompatActivity).supportFragmentManager
        var fragment = sfm.findFragmentByTag(TINDER_FRAGMENT)
        if (fragment == null) {
            fragment = ActivityProxyFragment()
            mFragment = fragment as ActivityProxyFragment
            sfm.beginTransaction().add(fragment, TINDER_FRAGMENT).commit()
            Log.i(TAG, "addFragment: ")
        }
    }
}

监听到Activity变化后,就可以注入我们的空Fragment

    public static class ConfigurationChangeFragment extends Fragment {
        private static final String TAG = "ConfigurationChangeFrag";
        private AssetManager mLastAssetManager;
        private int mLastUiMode;

        private IOnUiModeChangeListener mListener;

        public ConfigurationChangeFragment() {

        }

        public void setOnUiModeChangeListener(IOnUiModeChangeListener listener) {
            this.mListener = listener;
        }

        @Override
        public void onAttach(@NonNull Context context) {
            super.onAttach(context);
            mLastAssetManager = context.getAssets();
            mLastUiMode = context.getResources().getConfiguration().uiMode;
            CommonUtilsLog.i(TAG, "onAttach: assetManager:" + context.getAssets());
        }

        @Override
        public void onConfigurationChanged(@NonNull Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            CommonUtilsLog.i(TAG, "onConfigurationChanged: mLastUiMode:" + mLastUiMode + ",newUiMode:" + newConfig.uiMode + ",mLastAssetManager:" + mLastAssetManager + ",assetManager:" + getContext().getAssets());
            if (mLastUiMode != newConfig.uiMode) {
                mLastAssetManager = getContext().getAssets();
                mLastUiMode = newConfig.uiMode;
                if (mListener != null) {
                    mListener.onUiModeChange(newConfig);
                }
            }
        }

        public void release() {
            mListener = null;
        }
    }

    interface IOnUiModeChangeListener {
        void onUiModeChange(Configuration newConfig);
    }

这样就达到了利用空Fragment监听configurationChange的目的;注入空Fragment要注意,一个Activity不要重复注入,还有多个Activity也不要重复注入,否则会造成资源的浪费和回调重复等问题,这里只是简单示例,大家自行研究怎么解决这些问题;

2.2 应用场景2–SDK打开特定应用或Activity

监听/获取TopActivity和添加Fragment方法同上,但Fragment实现有所不同,如下:


class ActivityProxyFragment : Fragment() {
    private lateinit var launcher: ActivityResultLauncher<Intent>
    private lateinit var mOnActivityResult: IOnActivityResultCallback
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val contract = object : ActivityResultContract<Intent, ActivityResult>() {
            override fun createIntent(context: Context, input: Intent): Intent {
                Log.i(TAG, "createIntent: ")
                return input
            }

            override fun parseResult(resultCode: Int, intent: Intent?): ActivityResult {
                Log.i(TAG, "parseResult: ")
                return ActivityResult(resultCode, intent)
            }

        }
        launcher = registerForActivityResult(contract) {
            it.data
            Log.i(TAG, "onActivityResult: resultCode:$it.resultCode")
            mOnActivityResult.onActivityResult(it.resultCode, it.data)
        }
    }

    fun startActivityForResult(
        intent: Intent,
        callback: IOnActivityResultCallback
    ) {
        mOnActivityResult = callback
        launcher.launch(intent)
    }

    interface IOnActivityResultCallback {

        fun onActivityResult(resultCode: Int, data: Intent?)
    }

    companion object {
        private const val TAG = "ActivityProxyFragment"
    }
}

这样,在你的SDK代码中,就可以通过该ProxyFragment调用startActivityForResult

        mFragment.startActivityForResult(
            anyIntent,
             object : ActivityProxyFragment.IOnActivityResultCallback {
            override fun onActivityResult(resultCode: Int, data: Intent?) {

            	//do sth 
            	}
         })


3.总结

实际fragment的应用场景还有很多,我这里只是简单举两个例子,实际场景可以让ProxyFragment尽可能的实现多种Activity的功能,然后注入。

此次分享到此结束,如有问题,希望大家批评指正,非常感谢。

恭祝各位看官老爷身体健康,诸事顺利,好运连绵😘😘😘

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值