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

深入解析Glide生命周期管理 自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。 阅读详情

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,onConfigurationChange,onRequestPermissionsResult等等,同时,它还可以调用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的功能,然后注入。

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

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

Android面试进阶:从八股文背诵到核心技术深度解析与实战应用 在移动开发领域,掌握核心机制与性能优化是构建高质量应用的基础。从Java/Kotlin语言特性到JVM内存模型,理解垃圾回收机制、并发编程原理是解决内存抖动和线程安全问题的关键。这些底层知识直接关联到Android开发中的性能表现与稳定性。深入Android Framework层,如Binder跨进程通信机制、View绘制链路及Activity生命周期管理,不仅是面试高频考点,更是优化应用启动速度、流畅度及架构设计的工程实践基础。通过剖析内存泄漏场景与LeakCanary等工具链,结合Handler机制、协 阅读详情

相关推荐

Android MVVM实战:LiveData与Data Binding原理与避坑指南

LiveData是Android Jetpack中专为UI生命周期设计的状态观察者,其核心价值在于自动绑定LifecycleOwner并精准解绑,避免内存泄漏;Data Binding则通过编译期生成ViewDataBinding类,将XML声明式逻辑与Java/Kotlin代码解耦,显著提升UI渲染性能与可维护性。二者协同构成轻量、稳定、易调试的MVVM落地方案,特别适用于电商、金融等对稳定性与迭代效率要求严苛的商用App开发。本文聚焦真实项目中的状态管理、双向绑定、生命周期感知及高频编译/运行时问题,提

weixin_34008805的博客 419

Glide(一)生命周期的监听

Glide对生命周期的监听

qq_41095045的博客 1405

Android DayNight主题原理与夜间模式避坑指南

Android夜间模式并非简单切换主题,而是基于系统UiMode和AppCompatDelegate协同工作的资源分发机制。其核心在于语义化颜色属性(如colorSurface)、动态资源加载(values-night映射)与运行时主题重载时机的精准配合。技术价值体现在提升可访问性、降低功耗及适配系统级深色主题趋势;典型应用场景包括金融、电商类App的UI一致性保障,以及自定义View和MPAndroidChart等第三方库的兼容性改造。本文深入解析MODE_NIGHT_YES的真实行为边界、主题继承链断裂

weixin_34034670的博客 374

glide的生命周期管理

glide生命周期管理、内存管理、缓存机制、加载器、观察者模式 前言:本系列博文主要通过借鉴其他优秀博文以及自己的实际开发经验综合得出,主要分析glide相关使用、机制以及设计模式等内容,相信这篇博文会让你对glide有更加深入的理解。本篇是系列文章的第二章。 篇二 glide的生命周期管理 前言:本篇博客将介绍glide的生命周期管理,如何与Fragment和Activity绑定的。 我们知道将 Activity/Fragment 对象作为参数传给Glide.with(context/fr..

居家小男的博客 1037

拼多多Android面试题及参考答案

Android 系统采用分层架构设计,从底层到上层依次为Linux 内核层硬件抽象层(HAL)系统运行时库层应用框架层应用层,共五层。位置:Linux 内核层与系统运行时库层之间,是“硬件与系统的隔离层”。核心作用:屏蔽硬件差异,为上层提供统一的硬件访问接口,解决 Android 开源与硬件厂商闭源的矛盾,具体功能如下:硬件能力抽象:将硬件的具体实现(如不同厂商的摄像头芯片、音频芯片)封装为标准化接口(如Camera HALAudio HAL。

大模型大数据攻城狮的专栏 1284

PCB设计实践(三十二)PCB设计遇到大电流时的设计技巧

本文系统阐述10A至数百安培PCB设计的六大关键技术。载流能力优化强调铜厚选择(2-4oz)、线宽计算及并联结构;热管理提出散热孔阵列、铜基板嵌入等方案;布局策略包括功率分区和低阻抗路径设计;材料工艺推荐铝基板、陶瓷基板等高效解决方案;安全设计涵盖电气隔离与保护电路;验证环节需结合热仿真与实测。典型150A电机驱动板案例显示,通过4oz铝基板、散热孔阵列等设计,可实现温升≤45℃的稳定运行。核心在于铜厚线宽协同、主动散热及严格验证。

致力于硬件设计、人工智能知识及技术的分享,不断鞭策自己成长,共同进步! 4229

Glide源码解析2 -- 生命周期原理

一 概述 Glide 中一个重要的特性就是Request可以绑定Activity或者fragment的onStart而resume,onStop而pause,onDestroy而clear,所以Glide可以节约流量内存,防止内存泄露,但是要注意不要传入在with()方法里传入application,不然就没办法对生命周期进行管理了。 二 核心类 RequestManager:实现了LifeCycleListener,主要作用是结合Activity或者Fragment的生命周期,对Request进行管理,

qq_39431405的博客 1916

博图编写温度程序_s7 smart200的CRC-16校验程序

最近做一个小项目,项目中采用485自由口通讯方式,使用一台西门子S7 smart200对一台冷水机做多个状态和温度做监控,并能对冷水机进行启停控制,和参数设置,因为冷水机的协议不是标准modbus格式,所以要自己编写通信协议。其中要用到CRC校验,在网上找了些别人写的程序,基本上用不了。只能自力更生了。首先,找到CRC校验的算法,并理解。 下面就是我找的算法(这个网上很多),1....

weixin_39539761的博客 3062

Glide图片加载回调监听

    前两篇文章从源码的角度对Glide的加载流程进行了分析,这篇文章将对Glide的回调进行总结。1、方法一:设置图片中监听    方法一使用的是SimpleTarget类,他继承自BaseTarget,需要重写onResourceReady方法,onResourceReady方法表示加载完成后的回调,下面列举了返回为Drawable和Bitmap两种形式的回调,除了支持回调onResourc...

一杯清泉 2万+

君正T31x metartc集成测试

metartc为国内杨大侠部分开源的一款用于嵌入式领域webrtc库,它与谷歌官方webrtc相比,编译到君正平台的可执行文件仅有5M即可实现webrtc的通信。1. 目前实现的是基于开源版v5.0-b0版本做的简单修改,官方的好几个版本都多少缺点东西,我这里给整理了一下。目前是局域网连接的webrtc,后续尝试走stun和turn试一下NAT穿越的效果。

fsmpeg的博客 3158

【FPGA的基础快速入门23--------OV5640摄像头VGA显示】

FPGA的基础学习--------OV5640摄像头VGA显示OV5640简介二级目录三级目录 OV5640简介 OV5640同OV7725一样,都是Omni Vision(豪威科技)公司生产的CMOS图像传感器。 OV5640支持更高的分辨率(500W像素)、采集速率,具有更高的图像处理性能,主要应用在手机、数码相机、电脑多媒体等领域。 OV5640支持LED补光、MIPI(移动产业处理器接口)输出接口和DVP(数字视频并行)输出接口选择、ISP(图像信号处理)以及AFC (自动聚焦控制)等功能。 OV

暮雨中的坚果的博客 7689

Android之Glide

从上面的源码分析就能看出来:1:当传入的是ApplicationContext的时候Glide是通过ApplicationLifecycle()来绑定生命周期的。2:当传入的不是ApplicationContext的时候Glide是通过创建隐藏的Fragment(RequestManagerFragment)利用内部持有的ActivityFragmentLifecycle再有RequestManager监听回调最终实现生命周期的自动绑定。

m0_64334943的博客 920

Java中使用工厂模式和策略模式优雅消除if-else语句(UML类图+案例分析)

在最近的后端开发中,多多少少会发现有很多if-else语句,如果条件过多则会造成整体代码看起来非常臃肿。本篇博客汇总了我对工厂模式和策略模式的理解,以及我是如何把它们巧妙运用在实际项目当中的一些技巧进行了分享,如有问题,欢迎评论区讨论!

黄团团的个人博客 2612

Android面试进阶:从生命周期到架构设计,掌握核心原理与工程实践

在Android开发领域,理解核心组件原理与系统机制是构建稳定、高性能应用的基础。Activity、Fragment等组件的生命周期管理,不仅是面试高频考点,更是处理页面状态、数据恢复与内存管理的工程实践核心。其背后涉及系统对应用进程与任务栈的调度原理,深刻理解这些机制,能有效避免内存泄漏与状态不一致问题,提升应用健壮性。随着Jetpack架构组件的普及,ViewModel、LiveData等现代技术方案,为数据驱动UI和生命周期感知编程提供了标准化支持,推动了MVVM等架构模式在工程中的落地。这些技术价值

weixin_33713350的博客 476

【STK】手把手教你利用STK进行进行光电红外仿真02-STK/EOIR模块属性之一 传感器选项设置

EOIR传感器可以从空间几何属性、光谱属性、光学属性、辐射属性四个方面进行设置,并且可以设置信号传播路径中的大气特性,包括大气模型、气溶胶模型、气象学可见性和大气湿度。在定义EOIR传感器时,需要Sensor——Definition属性页中,将Sensor Type设置为EOIR。单击下面的按钮打开传感器的EOIR配置页,可以对传感器的属性进行配置,此外,还可以在场景中视情况添加相关的中心体。路径辐射损耗影响上述特性的计算,计算的结果考虑了传感器、目标位置的影响,但是还没考虑地球临边背景的影响。

weixin_44184852的博客 3200

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的远距离停车位检测系统(深度学习代码+UI界面+训练数据集)

本文详细介绍了基于YOLOv5/YOLOv6/YOLOv7/YOLOv8深度学习模型的远距离停车位检测系统的完整实现方案。该系统能够准确识别200米范围内的停车位状态,为智能停车场管理系统、自动驾驶车辆提供关键的视觉感知能力。文章涵盖算法原理、数据集构建、模型训练、系统实现及优化策略,并提供完整的代码实现和UI界面设计。关键词:YOLO系列,深度学习,停车位检测,计算机视觉,智能交通系统pythonimport cv2import os"""创建数据存储目录""""""定时采集图像"""

YOLO 185

2023年Android开发入门指南:从零基础到精通的核心路径

移动应用开发作为现代软件工程的重要分支,其核心在于构建高效、稳定的用户界面与数据交互系统。Android开发基于Java/Kotlin语言体系,通过四大组件、UI绘制原理和数据存储机制等技术模块,实现了跨设备平台的应用程序部署。在工程实践中,掌握MVVM架构、性能优化和现代UI框架Jetpack Compose等技术,能够显著提升应用的可维护性和用户体验。当前Android生态已进入成熟发展阶段,市场对具备系统原理理解和复杂问题解决能力的工程师需求持续增长,学习Android开发依然是进入移动开发领域的有效

weixin_34124651的博客 322

YOLOv11涨点改进 | 全网独家下采样改进、细节涨点篇 | TGRS 2025 | 引入PWD参数化小波下采样模块,减少下采样过程中小目标的关键细节丢失,即插即用,助力高效涨点发论文

本文提出了一种改进YOLOv11小目标检测性能的参数化小波下采样(PWD)模块。PWD通过小波变换保留目标细节信息,增强频率域特征表达,有效解决了传统下采样导致的小目标信息丢失问题。该模块采用双分支设计,结合自适应频率选择和空间补偿机制,在红外图像和低光场景中表现出更强的抗干扰能力。实验表明,PWD能显著提升YOLOv11对弱纹理和低对比度目标的检测精度,同时保持计算效率。文章详细介绍了PWD的结构原理、实现代码及在YOLOv11中的集成方法,为小目标检测提供了有效的改进方案。

Ai缝合怪、助力小伙伴高效发论文 232

2017年欢聚时代Android校招笔试题型深度复盘

Android开发进阶不仅要求掌握四大组件的使用,更需要对底层原理有系统认知。例如,Binder作为Android IPC的核心机制,通过mmap实现一次拷贝,保障跨进程通信的性能与安全;Handler消息机制则通过Looper与MessageQueue驱动主线程任务调度。性能优化中的内存泄漏、布局绘制等问题,直接影响应用用户体验。这些知识点在移动互联网时代成为Android工程师校招笔试的高频考点。本文基于欢聚时代2017年Android校招笔试A卷,复盘其题型结构与考察重点,涵盖Java基础、并发、四大

weixin_34248023的博客 442

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Android DayNight主题系统全解析:从原理到全链路适配

Android DayNight主题是基于系统UiMode的动态资源调度机制,其核心在于Theme继承体系与AppCompatDelegate的生命周期协同。它并非简单切换两套颜色,而是通过语义化属性(如?attr/colorSurface)实现亮/暗模式下UI元素的自动映射,依托Configuration变更触发Activity重建与资源重载。该机制显著提升可访问性与视觉一致性,广泛应用于深色模式、省电优化及无障碍场景。本文深入剖析DayNight主题的资源加载原理、AppCompatDelegate控制

weixin_30621711的博客 357

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

android 面试题

ContextImpl.startActivity → Instrumentation.execStartActivity → AMS.startActivity → 校验权限、创建 ActivityRecord、Pause 当前 Activity → ApplicationThread.scheduleTransaction → ActivityThread.H → LaunchActivityItem → performLaunchActivity(创建 Activity、调用 onCreate)。

qq_25657125的博客 397

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

面试题kkk

这篇文章摘要主要涵盖了Android开发中的核心知识点和技术难点,包括数据结构、Java与Kotlin语言特性、多线程与并发、内存管理、安卓组件与UI、IPC通信、数据库、多媒体处理、设计模式、性能优化、跨端开发等多个方面。文章详细解析了常见数据结构的使用与实现、JVM机制、内存泄漏分析与解决方案、Activity生命周期、事件分发机制、Handler原理、音视频处理、设计模式应用等核心内容,并提供了实际项目中的技术卡点与解决方案。此外,还涉及了性能优化策略、跨端开发差异、技术方案设计思路以及Git常用命令

mix39的博客 930

Android开发环境搭建与核心组件解析

Android开发环境搭建是移动应用开发的基础环节,其中Android Studio作为官方IDE集成了代码编辑、调试和性能分析工具链。开发环境配置涉及SDK管理、模拟器创建和网络代理设置等关键技术点,合理的工具链配置能显著提升开发效率。在Android框架层面,Activity生命周期管理、Service后台任务处理以及广播机制构成了应用的基础架构,这些核心组件通过特定的回调机制实现系统与应用的交互。随着Android系统版本迭代,运行时权限管理、后台限制等安全机制要求开发者遵循最佳实践。掌握ADB调试工

weixin_34185320的博客 427

Android开发瓶颈突破指南:从环境搭建到架构优化的实战路径

在移动应用开发领域,Android系统以其开放性占据重要地位,其技术栈的复杂性常使开发者面临多重瓶颈。从构建工具链的配置原理入手,理解Gradle依赖管理与版本兼容机制是项目稳定的基础。掌握性能优化技术,如内存管理与渲染管线分析,能显著提升应用流畅度与用户体验。这些核心能力在电商、社交等高频应用场景中至关重要,直接关系到用户留存与业务增长。本文聚焦Android开发中的典型挑战,通过剖析RecyclerView优化与架构模式选型等热词,为开发者提供从环境调试到系统底层的系统性突破方案。

weixin_30911451的博客 370

移动端开发面试核心考点复盘:从奇安信笔试题看基础与Vue跨端准备

移动端开发岗位的面试,往往不局限于单一技术栈,而是对计算机基础、工程实践和跨端能力的综合考察。理解操作系统中的进程线程、网络中的TCP/HTTP协议、数据结构中的链表与LRU,是构建稳定App的底层支撑。扎实的基础知识不仅决定笔试成绩,更影响着后续性能优化和复杂问题排查的深度。在实际项目中,Vue等跨端框架的兴起,使得移动端与前端边界日益模糊,掌握生命周期、响应式原理和组件通信,成为应对多端业务需求的必备技能。无论是准备春招秋招中的移动端开发笔试,还是系统梳理自身技术盲区,从经典真题出发复盘高频考点与答题思

weixin_30673611的博客 355

Android面试核心:Handler、RecyclerView与内存泄漏实战解析

在Android开发中,多线程通信与UI渲染是构建流畅应用的核心基础。Handler机制作为Android的“中枢神经系统”,其基于Looper、MessageQueue的单线程消息循环模型,是实现线程间通信、保证UI线程安全的关键。理解其原理,特别是ThreadLocal的作用和内存泄漏的成因,是高级工程师的必备技能。在UI层面,RecyclerView通过其四级缓存机制(包括Scrap、Cache、RecycledViewPool等)高效管理视图复用,大幅提升了列表滚动的性能,这是优化应用流畅度的关键技

weixin_34198453的博客 408
上一篇: Android OCR && 谷歌OCR TextRecognition用法介绍
下一篇: 插件化换肤原理——黑夜模式(深色模式)实现
cry kid
博客等级 码龄10年 144粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值