【听书源码实例】【指数宝源码】【tcp/ip 源码】fragment源码分析(一) 构造
1.Lifecycle
2.Androidç»ä»¶ä¹Fragmentï¼ä¸ï¼---åºç¡ç¥è¯ä¸è¿ç¨
3.Navigation源码解析及自定义FragmentNavigator详解
4.vue早期源码学习系列之四:如何实现动态数据绑定
5.从源码方面来分析Fragment管理中 Add() 方法
6.Android-Fragment源码分析
Lifecycle
Androidç¥è¯æ»ç»ç±»è®²è§£
å¨ComponentActivity ä¸çonCretaeæ¹æ³
ReportFragment ç±»æ¯ä¸ä¸ªFragmentï¼å®è´è´£åæ´¾çå½å¨æçæ¶é´ï¼injectIfNeededIn()å°±æ¯å¨å½åçActivityéæ·»å ä¸ä¸ªReportFragmentã
LifecycleRegister ç±»ä¸çaddObserveræ¹æ³
æ们ç LifecycleRegistry ä¸çå é¨ç±» ObserverWithState çå建
æ§è¡ Lifecycling.lifecycleEventObserver
å建 ReflectiveGenericLifecycleObserver è§å¯è
æ¥ä¸æ¥ç ClassesInfoCache ç±»çæ¹æ³
ç¶å Event åçååçæ¶åä¼ä» mCallbackMap ä¸æ¿å»å¯¹åºçclassæ件ï¼ç¶åéè¿åå°æ§è¡å¯¹åºçå½å¨ææ¹æ³ãæºç åæå¦ä¸ï¼
ä½ ä¼åç°é½è°ç¨äºdispatch()æ¹æ³ï¼èdispatch()æ¹æ³åä¼å¤æActivityæ¯å¦å®ç°äºLifecycleOwneræ¥å£ï¼å¦æå®ç°äºè¯¥æ¥å£å°±è°ç¨ LifecycleRegister#handleLifecycleEvent() ï¼è¿æ ·çå½å¨æçç¶æå°±ä¼åç±LifecycleRegistryéç¥ç»å个 LifecycleObserver ä»èè°ç¨å ¶ä¸å¯¹åº Lifecycle.Event çæ¹æ³ãè¿ç§éè¿Fragmentæ¥æç¥Activityçå½å¨æçæ¹æ³å ¶å®å¨Glideçä¸ä¹æ¯æä½ç°çã
æ们è¿è¾¹åªçåè¿æµç¨ï¼åéæµç¨åç
ObserverWithState æ¯ LifecycleRegistry çå®ç°ç±»
æ ¹æ®åé¢æ·»å è§å¯è åæï¼æ们çå°ä¼è¿å ¥ ReflectiveGenericLifecycleObserver ä¸æ§è¡ onStateChanged
æ§è¡ ClassesInfoCache å é¨ç±» CallbackInfo#invokeCallbacks
å¨ ClassesInfoCache å é¨ç±» MethodReference#invokeCallback æ们å¯ä»¥çå°éè¿åå°æ§è¡çå½å¨ææ¹æ³
å®ç° LifecycleObserver çå®ç°
使ç¨
Androidç»ä»¶ä¹Fragmentï¼ä¸ï¼---åºç¡ç¥è¯ä¸è¿ç¨
Fragmentæ¯Android3.0åå¼å ¥çä¸ä¸ªæ°çAPIï¼ä»åºç°çåè¡·æ¯ä¸ºäºéåºå¤§å±å¹çå¹³æ¿çµèï¼ å½ç¶ç°å¨ä»ä»ç¶æ¯å¹³æ¿APP UI设计çå® å¿ï¼èä¸æ们æ®éææºå¼åä¹ä¼å å ¥è¿ä¸ªFragmentï¼ æ们å¯ä»¥æä»çæä¸ä¸ªå°åçActivityï¼å称Activityç段ï¼æ³æ³ï¼å¦æä¸ä¸ªå¾å¤§ççé¢ï¼æ们 å°±ä¸ä¸ªå¸å±ï¼åèµ·çé¢æ¥ä¼æå¤éº»ç¦ï¼èä¸å¦æç»ä»¶å¤çè¯æ¯ç®¡çèµ·æ¥ä¹å¾éº»ç¦ï¼è使ç¨Fragment æ们å¯ä»¥æå±å¹ååæå åï¼ç¶åè¿è¡åç»ï¼è¿è¡ä¸ä¸ªæ¨¡ååç管çï¼ä»èå¯ä»¥æ´å æ¹ä¾¿çå¨ è¿è¡è¿ç¨ä¸å¨æå°æ´æ°Activityçç¨æ·çé¢ï¼å¦å¤Fragment并ä¸è½åç¬ä½¿ç¨ï¼ä»éè¦åµå¥å¨Activity ä¸ä½¿ç¨ï¼å°½ç®¡ä»æ¥æèªå·±ççå½å¨æï¼ä½æ¯è¿æ¯ä¼åå°å®¿ä¸»Activityççå½å¨æçå½±åï¼æ¯å¦Activity 被destoryéæ¯äºï¼ä»ä¹ä¼è·çéæ¯ï¼å¼ç¨å®æ¹çä¸å¼ å¾çï¼å ¶å®å·²ç»è¯´æé®é¢äºï¼å°±æ¯ä¸ºäºæ´å¥½çéé 大å±ï¼å¨å¤§å±çæ¶åï¼ä¸éè¦å»å¨ä¸ä¸ªactivityå é¨éè¿å¤æçå¸å±åçé¢å»å®ç°ï¼åªéè¦å»å¨ä¸ä¸ªactivityå é¨ï¼éè¿å¤ä¸ªfragmentæ¥åçé¢å¸å±å®ç°å³å¯ï¼èä¸é对äºå¤ä¸ªfragmentæ¥è¯´ï¼ æ¯ä¸ªfragmentæåç¬ççå½å¨æï¼
Demoæ ·ä¾ï¼æ们å¨ä¸ä¸ªçé¢ä¸ï¼æä¸ä¸ä¸¤ä¸ªfragmentï¼å¦å¾æ示ï¼
Step 2: Fragmentå建ï¼è§å¾å è½½ï¼æ°æ®èµå¼
BlankFragment .java
Step 3: Activityå¨onCreate( )æ¹æ³ä¸è°ç¨setContentView()ä¹åè°ç¨FragmentTransaction è¿è¡äºå¡æ交
FragmentTestActivity.java
å¨xmlä¸å£°æ两个fragmentï¼æå®ä¸ºå ·ä½çfragment
Step 1:å®ä¹Fragmentçå¸å±ï¼å°±æ¯fragmentæ¾ç¤ºå 容ç
Step 2:èªå®ä¹ä¸ä¸ªFragmentç±»,源码éè¦ç»§æ¿Fragmentæè ä»çåç±»,éåonCreateView()æ¹æ³ å¨è¯¥æ¹æ³ä¸è°ç¨:inflater.inflate()æ¹æ³å è½½Fragmentçå¸å±æ件,æ¥çè¿åå è½½çview对象
BlankFragment.java
Step 3:å¨éè¦å è½½FragmentçActivity对åºçå¸å±æ件ä¸æ·»å fragmentçæ ç¾ï¼ è®°ä½ï¼nameå±æ§æ¯å ¨éå®ç±»åå¦ï¼å°±æ¯è¦å å«Fragmentçå åï¼å¦:
Step 4: Activityå¨onCreate( )æ¹æ³ä¸è°ç¨setContentView()å è½½å¸å±æ件å³å¯!
é对å¨ä¸ä¸ªActivityä¸çæ个Layoutä¸åæ¢Fragment,,æ é两ç§æ¹æ³ï¼
æ们èªå·±çä¸ä¸æ¹æ³æ³¨é
æºç æ¹æ³æ³¨ééé¢è¯´çå¾æç½ï¼è¿ä¸ªæ¹æ³ä¼ç§»é¤ææçfragmentï¼ç¶åæ·»å å½åçfragmentã
è¿æ¶å为两ç§æ åµï¼ä¸ç§æ¯fragmentå·²æ并ä¸å¨åå°å±ç¤ºï¼ä¸ç§æ¯æªææè å¨åå°ï¼é对äºåè ï¼æ¤æ¶replaceï¼çå½å¨æä¸ä¼åçååï¼é对åè ï¼çå½å¨æä¼éæ°èµ°
å为两ç§æ åµï¼ä¸ç§fragmentå·²åå¨ï¼ä¸ç§æªåå¨ï¼é对äºåè ï¼çå½å¨ææ ååï¼ä½æ¯ä¼åè°onHiddenChangedæ¹æ³ï¼é对äºåè ï¼çå½å¨æä¼å建ä¸æ¬¡ã
1.Fragmentæ¯Googleå®æ¹å¼å ¥çä¸ä¸ªä¸ºäºéé 大å±ãå¤é¡µé¢çä¸ä¸ªç»ä»¶ãæ¨å¯ä»¥ç解为å®å°±æ¯ä¸ä¸ªç±»èå·²ï¼åªä¸è¿éé¢å å«äºViewï¼å¹¶ä¸ä¸activityççå½å¨æè¿è¡äºå ³èã
2.å¨æå è½½ä¸éæå è½½ç¸å¯¹æ¥è¯´ï¼å»ºè®®ä½¿ç¨å¨æå è½½ï¼éæå è½½åºå®å¨äºxmlæ件ä¸ï¼æ°¸è¿ä¸åã
3.replaceçfragmentå¦æä¸å¨åå°ï¼ä¼æ§è¡ææçå½å¨æï¼åä¹ä¸ä¼æ§è¡ä»»ä½çå½å¨ææ¹æ³ï¼hide+showçå½å¨æ并ä¸ä¼åçååï¼ä½æ¯ä¼åè°onHiddenChangedæ¹æ³ï¼å¨å®é å¼åä¸ï¼å»ºè®®addä¹åï¼ä½¿ç¨hide+showæ¥æä½fragmentï¼ä¸æ¹é¢åå°èµæºçéå¤å è½½åå建ï¼å¦å¤ä¸æ¹é¢æåç¨æ·ä½éªæã
4.fragmentççå½å¨æ大ä½ä¸åactivityä¸è´ï¼ä½æ¯åæååæå¤äºä¸äºä¸è¥¿ï¼å 为fragmentå é¨æviewï¼é£ä¹è¿ä¸ªviewéè¦è¿è¡å建ãç¶åæ·»å å°activityå é¨ï¼æ以ç¸åºçå¨onCreateä¸onStartä¹é´å°±å¤äºå 个æ¹æ³-onCreateViewãonViewCreatedãç¸åçéçï¼fragmentçviewä¸activity解ç»ï¼ä¹ç¸åºçå¨onStopä¸onDestoryä¹é´å¤ä¸ªæ¹æ³-onDestroyViewãonAttachä¸onDetachå¯ä»¥ç解为è§å¾ä¸activity产çå ³èåæ¥è§¦å ³èï¼æ¯æå¼å§åæåçæ¥éª¤ã
Demoå°å
Navigation源码解析及自定义FragmentNavigator详解
谷歌推出的Navigation主要目标是统一应用内页面跳转行为。使用方法简单,分析新项目选择Bottom Navigation Activity,构造系统自动生成页面逻辑。源码
Navigation源码设计简洁,分析包含多个关键类。构造听书源码实例其中,源码NavHostFragment是分析直接在XML文件中定义的,其生命周期方法onCreate中直接创建了NavHostController,构造并通过findNavController暴露给外部调用者。源码NavHostController继承自NavController。分析在此过程中,构造通过navController获取NavigatorProvider并添加了两个Navigator:DialogFragmentNavigator和FragmentNavigator。源码NavController构造方法中还额外添加了两个Navigator,分析分别对应DialogFragment、构造Fragment和Activity的页面跳转。NavGraphNavigator用于在XML配置的navGraph与根节点文件中的startDestination之间实现跳转,功能单一。
各个Navigator通过重写navigate方法实现各自的跳转逻辑。FragmentNavigator的关键实现在于注释1处,使用replace加载Fragment,这不符合实际开发需求。文章后续将解释如何自定义FragmentNavigator以避免Fragment在切换时执行生命周期。
NavigatorProvider内部维护了一个HashMap存储相关Navigator信息,通过获取Navigator的注解Name作为键和getClass作为值进行存储。在onCreate方法中,mNavController调用了setGraph,解析XML配置的mobile_navigation节点信息文件,根据不同的指数宝源码节点各自解析。通过获取NavInflater进行解析,返回NavGraph,NavGraph继承自NavDestination,保存了所有解析出的节点信息。
总结,通过NavHostFragment获取到NavContorl并存储了相关Navigator信息。通过各自navigate方法进行页面跳转,通过setGraph解析配置的页面节点信息并封装为NavGraph对象。其中,通过SparseArray存储Destination信息。
自定义Navigator实现思路主要在于继承现有FragmentNavigator并重写其navigate方法,将replace方法替换为show和hide方法,完成Fragment切换。通过@Navigator.Name(value)注解标记自定义类为Navigator,加入NavigatorProvider中即可识别。自定义Navigator核心代码实现后,需调整mobile_navigation节点中的fragment为fixFragment,并删除布局文件中NavHostFragment节点信息,手动关联FixFragmentNavigator与NavControl,完成Fragment切换时生命周期不会重新执行。
vue早期源码学习系列之四:如何实现动态数据绑定
本系列更多文章,请查阅我的博客:GitHub - youngwind/blog: 梁少峰的个人博客。或扫描下方二维码关注公众号“前端控”,欢迎交流讨论!
在前一篇中,我们学习了如何监听数据变化以及使用观察者模式和事件传递响应变化事件。今天,我们将探讨如何基于watch库实现动态数据绑定。tcp/ip 源码
我们可以将问题具体化为一个例子:如何实现当user.name或user.age发生变化时,HTML上的DOM元素也能相应地改变?
最初,我采取了以下方法:在数据顶层注册一个事件,当任意属性改变时,重新遍历DOM模板,将{ { user.name}}等转换为实际值,在内存中拼接成fragment,最后将新fragment替换掉原有的DOM结构。这种方法虽然简单,但存在不少问题。
基于上述问题,我们需要改进这种做法。为此,我们引入了Directive(指令)的概念,其构造函数和原型方法如下所示。关键实现思路是:在遍历DOM模板的过程中,当遍历到文本节点:"{ { name}}"时,先将其中的表达式"name"匹配出来,然后新建一个空的textNode,插入到这个文本节点的前面,最后移除这个文本节点。这样,就实现了用一个程序生成的textNode代替原来的textNode,从而实现每个textNode都跟它的表达式一一对应起来。
然而,这种方法仍然存在问题。为了解决这些问题,我们引入了Binding和Watcher这两个“类”。MySQL源码扩展Binding用于解决键值索引,Watcher用于解决$watch。Binding、Watcher和Directive三者之间的关系如下:(此处插入)
从图中可以看出,有一个_rootBind对象,其属性是按照DOM模板中用到的数据层层深入排列下去的。在每个属性上都有一个_subs数组,这个数组表示订阅的意思,里面存放的是一系列Watcher。Watcher既可以装载Directive,也可以装载$watch。这就是vue实现动态数据绑定的三大核心概念。
学习Vue.js,我checkout的是vue的这个版本。相比于之前的学习,代码量大幅增加,从七八百行增加到差不多五千行。特别是Binding、Watcher和Directive这几个核心概念,一开始让人难以理解。经过多日的思考和不断调试,我才逐渐明白。
此外,通过Binding、Watcher、Directive构建的动态数据绑定体系还存在一个重大缺陷,我们将在下一篇文章中专门阐述。
从源码方面来分析Fragment管理中 Add() 方法
本文深入解析了Android中Fragment管理中的laya+源码关键方法——Add()。Add()方法作为添加Fragment的基础操作,其用法直观且简便。例如,向Activity中添加一个Fragment的代码如下:
getSupportFragmentManager().beginTransaction().add(R.id.fragmenta,new FragmentA()).commit();
在实际应用中,我们通常需要添加多个Fragment以实现界面的动态切换。如微信底部导航栏,每个按钮对应一个不同的Fragment。通过Add()方法配合hide和show,可以实现Fragment之间的平滑切换。
我们以两个Fragment为例,实现了MainActivity的布局和内容。通过简单的代码实现,我们观察到Fragment的生命周期。初次运行时,输出如下日志;点击FragmentB后,再次点击FragmentA和B时,日志显示FragmentA和B只会初始化一次,证明了通过hide和show进行切换时,初始化效果的实现。
接着,我们介绍了replace方法。replace方法实际上包含了remove和add的组合,用于在FragmentManager中替换Fragment。若切换到下一个Fragment时,上一个Fragment不再需要,可以使用replace方法。若需要保留上一个Fragment,API提供了相应的addBackToStack方法。
修改MainActivity代码中的逻辑,再次执行并观察日志。在初次初始化时,日志保持一致;点击FragmentB后,发现Fragment调用了destroy方法,而点击FragmentA时,界面显示的仍是FragmentB。此时,我们修改了逻辑,使得每次切换时,Fragment都会重新调用onCreateView到onDestroyView的所有方法,实现了布局层的完整销毁和重建。
特别提醒,当进行Fragment嵌套时,若需要在返回时跳过中间的Fragment,使用FragmentManager.popBackStackImmediate方法可以实现弹出指定TAG的Fragment,并清除其之前的Fragment,从而实现更深层次的返回。
本文代码示例和完整代码资源可以通过点击此处传送门获取,或者查看下方小卡片。
最后,我想强调的是,技术的追求永无止境。对于程序员而言,不断提升自己,对每一行代码、每一个工具负责,深入理解其底层原理,是提升技术能力的关键。Android架构师之路漫长而艰辛,与君共勉。
Android-Fragment源码分析
Fragment是Android系统为了提高应用性能和降低资源消耗而引入的一种更轻量级的组件,它允许开发者在同一个Activity中加载多个UI组件,实现页面的切换与回退。Fragment可以看作是Activity的一个子部分,它有自己的生命周期和内容视图。
在实际应用中,Fragment可以用于构建动态、可复用的UI组件,例如聊天应用中,左右两边的布局(联系人列表和聊天框)可以分别通过Fragment来实现,通过动态地更换Fragment,达到页面的切换效果,而无需整个页面的刷新或重新加载。
在实现上,v4.Fragment与app.Fragment主要区别在于兼容性。app.Fragment主要面向Android 3.0及以上版本,而v4.Fragment(即支持包Fragment)则旨在提供向下兼容性,支持Android 1.6及更高版本。使用v4.Fragment时,需要继承FragmentActivity并使用getSupportFragmentManager()方法获取FragmentManager对象。尽管从API层面看,两者差异不大,但官方倾向于推荐使用v4.Fragment,以确保更好的兼容性和性能优化。
下面的示例展示了如何使用v4.Fragment实现页面的加载与切换。通过创建Fragment和FragmentActivity,我们可以加载特定的Fragment,并在不同Fragment间进行切换。
在FragmentDemo的布局文件中,定义了Fragment容器。
在Fragment代码中,定义了具体的业务逻辑和视图渲染,如初始化界面数据、响应用户事件等。
在Activity代码中,通过FragmentManager的beginTransaction方法,加载指定的Fragment实例,并在需要时切换到不同Fragment,实现页面的动态更新。
从官方的建议来看,v4.Fragment已经成为推荐的使用方式,因为它在兼容性、性能和功能方面都更优于app.Fragment。随着Android系统的迭代,使用v4.Fragment能确保应用在不同版本的Android设备上均能获得良好的运行效果。
在Fragment的生命周期管理中,Fragment与Activity的生命周期紧密关联。通过FragmentManager的操作,如commit、replace等,可以将Fragment加入到Activity的堆栈中,实现页面的加载与切换。当用户需要返回时,系统会自动将当前Fragment从堆栈中移除,从而实现页面的回退。
深入Fragment源码分析,我们可以了解其如何在底层实现这些功能。Fragment的初始化、加载、切换等过程涉及到多个关键类和方法,如FragmentManager、FragmentTransaction、BackStackRecord等。通过这些组件的协作,Fragment能够实现与Activity的生命周期同步,确保用户界面的流畅性和高效性。
在实际开发中,使用Fragment可以显著提高应用的响应速度和用户体验。通过动态加载和切换不同的Fragment,开发者可以构建出更加灵活、高效的应用架构,同时减少资源的消耗,提高应用的性能。
URP管线PBR源码剖析(上)
URP管线与PBR算法的联系并不直接,但新版本的代码结构和算法有了显著变化。本文将深入剖析URP管线下的内置PBR着色器,对比旧版本,探讨主要区别。 此篇内容旨在学习和解答问题,期待大家的反馈和讨论。以下分析分为三步:梳理UniversalFragmentPBR函数的功能和代码结构
解析通用PBR算法
详解ClearCoatPBR算法
首先,UniversalFragmentPBR的主要工作分为数据准备和光照计算。数据准备包括初始化BRDF数据、ClearCoat BRDF数据、shadowMask、获取主光源信息和处理SSAO等。光照计算则涵盖了间接光和直接光的计算,如GI、主光、额外像素和顶点光照等。 通用PBR算法的关键部分包括BRDF数据初始化,其中金属和非金属材质的处理有所不同;间接光的计算涉及漫反射和镜面反射;主光光照计算使用了改良的Lambert和Cook-Torrance模型;额外光计算则根据光源类型进行相应调整。 URP版本与旧版的不同点在于支持ClearCoat材质、ShadowMask功能、SSAO效果的整合,以及额外光处理的简化。整体来看,新版本的PBR算法更加灵活且高效。