总结
算法知识点繁多,企业考察的题目千变万化,面对越来越近的“金九银十”,我给大家准备好了一套比较完善的学习方法,希望能帮助大家在有限的时间里尽可能系统快速的恶补算法,通过高效的学习来提高大家面试中算法模块的通过率。
这一套学习资料既有文字档也有视频,里面不仅仅有关键知识点的整理,还有案例的算法相关部分的讲解,可以帮助大家更好更全面的进行学习,二者搭配起来学习效果会更好。
部分资料展示:
有了这套学习资料,坚持刷题一周,你就会发现自己的算法知识体系有明显的完善,离大厂Offer的距离更加近。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
如果把上面的 FactoryActivity
修改为继承 AppCompatActivity
,我们会看到 TextView
确实变成了 RedTextView
。但是我们添加的 Button
仍然是 Button,并没有变成 AppCompatButton
,这是为什么?
AppCompatActivity
的 onCreate
方法的前两行是:
getDelegate()
根据 api 版本的不同返回对应的代理类(AppCompatDelegateImplV14
, AppCompatDelegateImplV23
, AppCompatDelegateImplN
等等)。
下一行代码 delegate.installViewFactory()
,当 layoutInflater.getFactory()
为空的时候,会调用 setFactory2
。如果不为空,什么都不会做。
所以 Button
没有发生变化的原因是,已经设置过了 Factory,导致 AppcompatActivity
自己的 factory 没有被 install。
注意,FactoryActivity
的 setFactory2()
方法是在 super.onCreate
之前调用的。如果不是的话,当父类是 AppcompatActivity
,setFactory2
会抛出异常。因为 AppCompatActivity
设置了自己的 Factory 。文档中是这样描述的:它不能为空,且只能被设置一次;在设置之后,你不能对 Factory 进行改变 。
三、如何兼容 AppCompatActivity 的 Factory2
如何既能使用自己的 Factory2,又能让 AppCompatActivity
保留自己的 Facotory 呢?下面给出几种解决方法。
(一)代理给 AppCompatDelegate
在 AppCompatDelegate
内部有一个 createView
方法,不要和 Factory
、Factory2
的 onCreateView
混淆。
我们仅仅只需要修改 setFactory2
,将不需要处理的情况代理给 AppCompatDelegate
:
运行一下,TextView
变成了 RedTextView
,Button
变成了 AppCompatButton
,成功!
(二)重写 viewInflaterClass
我们看一下 AppCompatDelegate
的 createView
方法,当 AppCompatViewInflater
没有初始化时,会通过反射创建。要初始化的类由 R.styleable.AppCompatTheme_viewInflaterClass
指定,默认就是 AppCompatViewInflater
。
对 FactoryActivity
的 theme 进行如下修改:
就可以让 AppCompatDelegate
使用我们自定义的 AppCompatViewInflater
的子类 CustomViewInflater
:
Google 的 Material Design Components 实际上就是使用这种方法来将 Button
修改为对应的 MaterialButton
,在 这里 可以看到 。
这个方法很强大,它可以让你的 App 使用 Material Design Components 这样的类库,却仅仅只需要设置合适的主题。
注意 AppCompatViewInflater
还提供了一个可以被重写的 createView()
方法,用来处理默认情况下没有被处理的新的组件。当 AppCompatViewInflater
没有处理特定的组件类型,就可以使用这个方法。
(三)自定义 LayoutInflater
第三种方法是重写 Activity
的 attachBaseContext
,改写 ContextThemeWrapper
的 getSystemService
方法,返回自定义的 LayoutInflater
。自定义的 LayoutInflater
可以重写 setFactory2
方法,加入自己的处理逻辑。这个方法是我从 ViewPump 学到的。
四、一些小细节
下面介绍了 AppCompatDelegate 在进行视图加载过程中的几个小细节。
(一)onCreateView
我们希望 Factory2
的 onCreateView
方法直接调用 createView
(代理给 AppCompatDelegate
那一小节中提到过) 。事实上,的确也是这么做的。但是代码中还多了一点东西 - 调用了 callActivityOnCreateView
。在 AppCompatDelegateImplV14
中是这样的:
看一下 LayoutInflater
的 源码 , createViewFromTag
尝试通过 factory 获取 view 。如果没有获取到,会使用 mPrivateFactory
。如果依旧没有获取到,会通过视图标签去创建 view 。mPrivateFactory
是在 Activity 中设置的。
有意思的是, mPrivateFactory
的作用是解析 fragment
标签。
在 API 14 之前,LayoutInflater
并没有提供 mPrivateFactory
让 Activity 可以有个兜底方案来创建 View 。因此,callActivityOnCreateView
在低版本中提供了这一功能。但这现在都没有关系了,反正 AppCompat 目前只兼容 Api 14+ 。
另一个有意思的知识点是 Window.Callback 。Window.Callback
是一个回调,让调用者可以拦截 key 的分发,面板,菜单等等。它让 AppCompatActivity 可以处理一些特定时间,例如菜单键,返回键等。
(二)createView
总的来说,AppCompatDelegateImplV9
做了两件事。首先,创建了 AppCompatViewInflater
或者在 theme 中指定的其他子类。第二,通过 inflater 创建 View 。
AppCompatViewInflater
的 createView
使用了正确的 Context
(考虑到支持 app:theme
和 android:theme
,需要对 Context 进行包装),根据组件名称创建对应的 AppCompat 组件(例如,如果是 TextView
,就调用 createTextView
方法返回 AppCompatTextView
)。
(三)支持 app:theme
从 Android 5.0 开始,可以给 View 设置 app:theme
以覆盖特定 View 及其子类的属性。AppCompat 通过继承父 View 的 context 在 Android 5.0 之前复制这一行为。
在 AppCompat 加载 View 之前,它先拿到父 View 的 Context,然后尝试创建一个 ContextThemeWrapper(android:theme
或者 app:theme
),保证使用正确的 context 来加载组件。
另外,如果开发者明确声明需要在资源中使用矢量图,AppCompat 在 Android 5.0 之前还提供了 TintContextWrapper
来包装 Context 。
(四)View 的创建和兜底
通过这些信息,系统已经准备好如何创建 View 了。
遍历支持的组件列表,对于通用的 View,如 TextView
, ImageView
,直接生成对应的 AppCompat 子类。如果是未知类型的 View,将使用正确的 Context 调用 createView
,默认返回 null,但一般会被 AppCompatViewInflater 的子类重写。
如果这时候 view 仍然是 null,会检查 view 的原始 context 是否和父 View 的 context 一致。这种情况会发生在子 View 的 android:theme
和 父 View 不一致。
在检查 android:onClick
之后,view 就被返回了。
五、总结和使用实例
总结一下,AppCompatActivity
通过给 LayoutInflater
设置 Factory2
来介入 View 的创建过程,以提供向后兼容性(为组件提供 tint,处理 android:theme
等)。它也保证了可扩展性,开发者可以进行一些定制处理。
除了 Appcompat,这一技巧被用来完成了更多有意思的事情。Probe (现已废弃) 提供了 OvermeasureInterceptor 来记录 View 的测量次数,LayoutBoundsInterceptor 来高亮 View 的边界。
Calligraphy 使用这一技巧方便的为 TextView 添加字体。它使用了ViewPump 库,在 wiki 中提供了一些可能的使用方式。
最后
今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。
最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
【Android核心高级技术PDF文档,BAT大厂面试真题解析】
【算法合集】
【延伸Android必备知识点】
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!