最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
当然我也为你们整理好了百度、阿里、腾讯、字节跳动等等互联网超级大厂的历年面试真题集锦。这也是我这些年来养成的习惯,一定要学会把好的东西,归纳整理,然后系统的消化吸收,这样才能极大的提高学习效率和成长进阶。碎片、零散化的东西,我觉得最没有价值的。就好比你给我一张扑克牌,我只会觉得它是一张废纸,但如果你给我一副扑克牌,它便有了它的价值。这和我们收集资料就要收集那些系统化的,是一个道理。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
}
if (count > 99 && !hasFire()) {
addFire()
setBadgeText(“99+”)
} else if (count <= 99 && hasFire()) {
removeFire()
}
if (count > 0 && !hasPaper()) {
addPaper()
} else if (count == 0 && hasPaper()) {
removePaper()
}
if (count <= 99) {
setBadgeText(“$count”)
}
}
弄清楚如何调整 UI 以使其呈现正确的状态,实际上可能还有很多极端情况,这个逻辑并不简单,但是这已经算是相对简单的例子了。而如果你用声明式的方式写这段逻辑那么会是这样的:
@Composable
fun BadgeEnvelope(count: Int) {
Envelope(fire = count > 99, paper = count > 0) {
if (count > 0) {
Badge(text = if (count > 99) “99+” else “$count”)
}
}
}
你会发现至少在UI操作上来说声明式编程要更加直观,更加简洁。
而UI开发者最关心的是什么呢?对于给定的数据UI该怎么显示?怎么响应事件让UI进行交互?UI随着时间应该怎样变化?
有了声明式编程,有了Jetpack Compose,我们不再需要考虑UI随时间的变化,这是最重要最关键的点,因为在我们拿到数据后我们就定义了它在各个状态下应该怎么展示,之后框架会控制如何从一个进入另一个状态,即 “根据提供的参数来描述UI”。组合式函数,是个函数定义,但是它在一个地方描述了UI所有可能的状态,而且是本地定义的,这就是组合(composition),因此有了Compose和@Composable这两个名字。
组合 vs 继承
组合(composition)和继承(Inheritance)是面向对象编程中最常见的关联关系,继承是扩展类功能最简单直接的方式,但是多继承弊端太大导致除了C++的大部分语言都是只允许单继承的,如果我们把View系统通过继承实现,那么就会出现类似这样的问题,如果我想要个Input,那么我继承View,如果我想要个ValidatedInput那么我继承Input,如果我想要个DateInput那么我继承ValidatedInput,如果我想要个DateRangeInput怎么办呢?
我不能继承DateInput因为我有两个Date,但我又想拥有DateInput的能力,所以,我们最终还是遇到了单继承的限制。而在Jetpack Compose中这个问题就很简单了,我们无非多组合一个DateInput而已。
封装
Jetpack Compose另一个做得比较好的地方就是封装,一个composable就是 给定参数,一个composable可以 管理状态,这是你开放你的 API 时唯一需要考虑的。另一方面,composable可以管理和创建状态,然后它可以将状态以及接收到的数据作为参数传递给其他composable,子composable也可以通过回调的方式通知你状态的更改。
重组
重组(Recomposition)最基本的就是任何组合式函数都有 随时被再次调用 的能力,这也就意味着,如果你有一个很大的层级结构,当一部分层级改变后,你不需要重建整个层级。你可以利用这个特性做一些大事,比如对于之前这样的操作:
fun bind(liveMsgs: LiveData) {
liveMsgs.observe(this) { msgs ->
updateBody(msgs)
}
}
我们观察这个LiveData,每次LiveData更新的时候都会调用我们传入的lambda,然后更新UI。但是这毕竟是异步回调的形式,不符合我们的习惯,而在Jetpack Compose中我们就可以把这个关系转换过来:
@Composable
fun Messages(liveMsgs: LiveData) {
val msgs = +observe(liveMsgs)
for (msg in msgs) {
Message(msg)
}
}
在这里我们调用了observe()函数,它做了两件事,首先是解封装LiveData来返回它的当前值,这也就意味着你可以在函数体中直接使用这个值。其次,它还隐式地将LiveData订阅到这个它会被解封装的组合式函数作用域中。这也就意味着,我们不再需要传递lambda表达式了,我们只需要知道这个组合式函数每次在LiveData变化时都会重组就行了。让我们再次比较上面两段代码,虽然在代码量上没有什么差异,但是在思想上后者要更加符合我们的思维习惯,更加直观。
数据驱动视图
数据驱动视图的思想既能简化UI操作又能保证数据展示的一致性,而Data Binding对于数据驱动视图的尝试虽然有效,但是并不是十分优雅,一个Model可以插入到XML中,可以进行一些简单的处理,而如果让视图跟随Model变化还需要将Model转化成Observable,这个转化是需要手动完成的。而Jetpack Compose对于数据驱动视图的尝试要更优雅一些,如这里的一个计数器功能:
@Composable
fun Counter() {
val count = +state { 0 }
Button(
text = “Count: ${count.value}”,
onClick = { count.value += 1 }
)
}
state函数可以直接返回包裹了给定值的State状态类实例,State类用了@Model注解,而@Model注解就意味着这个类的所有属性的读写操作都是observable的,Jetpack Compose做得就是当你执行你的组合式函数时,如果你读取了一些Model实例,那么Jetpack Compose将自动订阅所在的作用域以便进行Model的读写。因此这个例子中的Counter是独立自给的,每次Model的值发生更改时Counter都会重组。
使用
–
组合式函数
Jetpack Compose是建立在组合式函数(composable functions)的基础上的,这些函数可以让你以编程的方式定义UI(通过描述它的形状和数据依赖),而不是关注UI的构建过程 一个组合式函数只能被另一个组合式函数调用,所以组合式函数需要添加@Composable注解。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting(“Android”)
}
}
}
@Composable
fun Greeting(name: String) {
Text(“Hello $name!”)
}
没有参数的组合式函数是可以直接预览的,只需要添加@Preview注解即可。
Jetpack Compose团队认为 “创建未被应用调用的单独的预览函数是最佳的做法,专门的预览函数不但可以提高性能,还可以方便地提供多个预览”,不过我觉得有点鸡肋,单个组合式函数应该可以自动或者手动预览,不应该书写额外的预览函数,而对于多个预览函数,应该属于UI测试的范畴,不需要也不应该出现在源码中。
布局
使用 Column() 函数可以竖向堆叠元素,可以通过它的 crossAxisSize 参数指定列的大小,通过它的 modifier 参数指定修饰样式。
Column(
crossAxisSize = LayoutSize.Expand,
modifier = Spacing(16.dp)
) {
Text(“A day in Shark Fin Cove”)
Text(“Davenport, California”)
Text(“December 2018”)
}
Container() 可以作为通用容器包裹和限制里面的元素。HeightSpacer()可以用作留白。Clip()可以裁剪,参数是用来裁剪的Shape,Shape是不可见的。MaterialTheme()可以给组件应用主题,然后就可以给文本应用样式了,如 Text(“A day in Shark Fin Cove”, style = +themeTextStyle { h6 }) 。
@Composable
private fun TopicItem(topicKey: String, itemTitle: String) {
val image = +imageResource(R.drawable.placeholder_1_1)
Padding(left = 16.dp, right = 16.dp) {
FlexRow(
crossAxisAlignment = CrossAxisAlignment.Center
最后
愿你有一天,真爱自己,善待自己。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
rossAxisAlignment = CrossAxisAlignment.Center
最后
愿你有一天,真爱自己,善待自己。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!