2024年安卓最全关于Android结构运用你是否真正的了解?(2),C# 多线程面试题

结尾

如何才能让我们在面试中对答如流呢?

答案当然是平时在工作或者学习中多提升自身实力的啦,那如何才能正确的学习,有方向的学习呢?为此我整理了一份Android学习资料路线:

这里是一份BAT大厂面试资料专题包:

好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划。来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

}

本地模型(与设计图一一对应)

LocalModel{

//将后端模型转换为本地模型

title = model.prefix + model.title

}

UI层

View{

textView = localModel.title

}

LocalModel相当于一个中间层,通过适配器模式将数据层与视图层做隔离。

前端引入Data Mapper后可以脱离后端进行开发,只要需求明确就可以做视图层的开发,完全不需要担心后端返回什么结构、字段。并且这种做法是一劳永逸的,比如后端需要对某些字段做调整,我们可以不假思索直奔数据层,涉及到的调整100%不会影响到视图层

注意点:

当下有一部分公司为了将前后端分离更彻底,由前端开发人员提供Java Bean(相当于LocalModel)的结构,好处也很明显,更多的业务内聚到后端,很大程度提升了业务的灵活性,毕竟App发一次版成本还是比较大的。面对这种情况我们其实没必要再编写Data Mapper。所以任何架构设计都要结合实际情况,适合自己的才是最好的。

1.5 无处安放的业务逻辑


关于业务逻辑其实是一个很笼统的概念,甚至可以将任意一行代码称之为业务逻辑,如此宽泛的概念我们该如何去理解?我先大致将它分为两个方面:

界面交互逻辑:视图层的交互逻辑,比如手势控制、吸顶悬浮等等都是根据业务需要实现的,所以严格来说这部分也属于业务逻辑。但这部分业务逻辑一般在视图层实现。

数据逻辑:这部分是大家常说的业务逻辑,属于强业务逻辑,比如根据不同用户类型获取不同数据、展示不同界面,加上Data Mapper一系列操作其实就是给后端兜底,帮他们补全剩余逻辑而已。为了方便大家理解下文我将数据逻辑统称为业务逻辑。

前面我们说到,Android开发应该具备数据层跟视图层,那业务逻辑放在哪一层比较合适呢?比如MVVM模式下大家都说将业务逻辑放到ViewModel处理,这么说也没有太大的问题,但如果一个界面足够复杂那对应的ViewModel代码可能会有成百上千行,看起来会很臃肿可读性也非常差。最重要的一点这些业务很难编写单元测试用例。

关于业务逻辑我建议单独写一个use case处理。

use case通常放在ViewModeler与数据层之间,业务逻辑以及Data Mapper都应该放在use case中,每一个行为对应一个use case。这样就解决了ViewModeler臃肿的问题,同时更方便编写测试用例。

注意点:

好的设计都是特定场景解决特定问题,过度设计不仅解决不了任何问题反而会增加开发成本。以我目前经验来看Android开发至少一半的场景都很简单:请求–>拿数据–>渲染视图最多再加个Data Mapper,流程很单一并且后期改动的可能也不太大,这种情况就没必要写一个use case,Data Mapper扔到数据层即可。

2 . 合理分层是给 数据驱动UI 做铺垫

==============================================================================

先说结论:数据驱动UI的本质是控制反转

2.1 什么是 控制反转?


控制即对程序流程的控制,一般由我们开发者承担,此过程为控制。但开发者是人所以不可避免出现错误,此时可以将角色做一个反转由成熟的框架负责整个流程,程序员只需要在框架预留的扩展点上,添加跟自己的业务代码,就可以利用框架来驱动整个程序流程的执行,此过程为反转。

控制反转概念和设计原则中的依赖倒置很相似,只是少了一个依赖抽象。

打个比方:

现有一个HTTP请求的需求,如果想自己维护HTTT链接、自己管理TCP Socket、自己处理HTTP缓存…就是整个HTTP协议全部自己封装,先不说这个工程能不能靠个人实现,就算实现也是漏洞百出,此时可以换个思路:通过OkHttp去实现,OkHttp是一个成熟的框架用它基本上不会出错。个人封装HTTP协议到使用OkHttp框架,这个过程在控制HTTP的角色上发生了一个反转,个人—>成熟的框架OkHttp即控制反转,好处也很明显,框架出错的概率远低于个人

2.2 什么是数据驱动UI?


通俗一点说就是当数据改变时对应的UI也要跟着变,反过来说当需要改变UI只需要改变对应的数据即可。现在比较流行的UI框架如Flutter、Compose、Vue其本质都是基于函数式编程实现数据驱动UI,它们共同的目的都是为了解决数据,UI一致性问题。

在当前的Android中可以使用DataBinding实现同样的效果,以Jetpack MVVM为例:ViewModel从Repository拿到数据暂存到ViewModel对应的ObservableFiled即可实现数据驱动UI,但前提是从Repository拿到的数据可以直接用,如果在Activity或者Adapter做数据二次处理再notify UI,已经违背数据驱动UI核心思想。所以想实现数据驱动UI必须要有合理的分层(UI层拿到的数据无需处理,可以直接用),Data Mapper恰好解决这一问题,同时也可规避大量编写BindAdapter的现状。

DataBinding并非函数式编程,它只是通过AbstractProcessor生成中间代码,将数据映射到XML中

2.3 为什么说数据驱动UI底层思想是控制反转?


当前Android生态能实现数据绑定UI的框架只有两个:DataBinding、Compose(暂不讨论)

在引入DataBinding之前渲染一条数据通常需要两步,如下:

var title = “iOS”

fun setTitle(){

//第一步更改数据源

title = “Android”

//第二个更改UI

textView = title

}

共需要两步更改数据源、更改UI,数据源跟UI有一个忘记修改便会出现BUG,千万不要说:“两个我都不会忘记修改”,当面临复杂的逻辑以及十几个甚至几十个的数据源很难保证不出错。这种问题可以通过DataBinding解决,只需更改对应的ObservableFiledUI便会同步修改,控制UI状态也从个人反转到的DataBinding,个人疏忽的事情DataBinding可不会。

所以说数据驱动UI底层思想是控制反转

2.4 为什么引入Diff?


引入diff之前:

RecyclerView想要实现动态删除、添加、更新需要分别手动更新数据和UI,这样在中间插了一道并且分别更新数据和UI已经违背了前面所说的数据驱动UI,而我们想要的是不管删除、添加或者更新只有一个入口,只要改变数据源就会驱动UI做更新,想要满足这一原则只能改变数据源后对RecyclerView做全部刷新,但这样会造成性能问题,复杂的界面会感到明显的卡顿。

引入diff之后:

Diff算法通过对oldItem和newItem做差异化比对,会自动更新改变的item,同时支持删除、添加的动画效果,这一特性解决了RecyclerView需要实现数据驱动UI的性能问题

3 为什么我建议使用 函数式编程

=========================================================================

3.1 什么是 函数式编程?


  • 一个入口,一个出口。

  • 不在函数链内部执行与运算本身无关的操作

  • 不在函数链内部使用外部变量(实际上这一条很难遵守,可以适当突破)

说得通俗点就是给定一个初始值,经过函数链的运行会得到一个目标值,运算的过程中外部没有插手的权限,同时不做与本身无关的操作,从根本上解决了不可预期错误的产生。

举个例子:

//Kotlin代码

listOf(10, 20).map {

it + 1

}.forEach {

Log.i(“list”, “$it”)

}

上面这种链式编程就是标准的函数式编程,输入到输出之间开发者根本没有插手的机会(即Log.i(…)之前开发者没有权限处理list),所以整个流程是100%安全的,RxJava、Flow、链式高阶函数都是标准的函数式编程,它们从规范层面解决数据安全问题。所以我建议在Kotlin中 碰到数据处理尽量使用链式高阶函数(RxJava、Kotlin Flow亦然)。

3.2 Android视图开发可以借鉴函数式编程思想


Android视图开发大都遵循如下流程:请求–>处理数据–>渲染UI,这一流程可以借鉴函数式编程,将请求作为入口,渲染作为出口,在这个流程中尽量不做与当前行为无关的事(这也要求ViewModel,Repository中的函数要符合单一原则)。这样说有点笼统,下面举个反例:

View{

//刷新

fun refresh(){

ViewModel.load(true)

}

//加载更多

fun loadMore(){

ViewModel.load(false)

}

}

ViewModel{

//加载数据

load(isRefresh){

if (isRefresh){

//刷新

}else{

//加载更多

}

}

}

View层有刷新、加载更多两种行为,load(isRefresh)一个入口,两个出口。面临的问题很明显,修改刷新或加载更多都会对对方产生影响,违反开闭原则中的闭(对修改关闭:行为没变不准修改源代码),导致存在不可预期的问题产生。可以借鉴函数式编程思想对其进行改进,将ViewModel的load函数拆分成refresh和loadMore,这样刷新和加载更多两种行为、两个入口、两个出口互不干涉,通过函数的衔接形成两条独立的业务链条。

函数式编程可以约束我们写出规范的代码,面对不能使用函数式编程的场景,我们可以尝试自我约束往函数式编程方向靠拢,大致也能实现相同的效果。

综上所述

=============================================================

  • 合理的分层可以提升复用性、降低模块间耦合性
  • Data Mapper 可以让视图层脱离于后端进行开发
  • 复杂的业务逻辑应该写到use case中
  • 数据驱动UI的本质是控制反转

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

七大模块学习资料:如NDK模块开发、Android框架体系架构…

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
第三,到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!
由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

第三*,到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值