最新Android知识笔记:对于Jetpack Compose的一次尝试,面试互联网公司怎么说

最后

其实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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值