第一行代码读书笔记 Kotlin Android

return operation(num1, num2)

}

7. 泛型和委托


7.1 泛型

  1. 给方法加泛型

fun method(param: T) : T {

return param;

}

  1. 给类加泛型

class MyClass {

fun method(param: T) : T {

return param;

}

}

7.2 委托

委托是一种设计模式,它的基本理念是: 操作对象自己不会去处理某段逻辑,而是会把工作委托给另外一个辅助对象去处理.

好处: 如果一个类,让大部分的方法实现都是调用辅助对象中的方法,而少部分的方法是自己实现的,这种情况,就是委托模式的意义所在.

  1. 类委托

kotlin支持类委托给另一个辅助对象,语法层面就支持,拥有辅助对象的所有功能,还能自己去实现或构建独有功能. 直接通过关键字by完成,简化自己去编写模板代码

//MySet中有所有Set接口中的功能,和HashSet保持一致, 并且isEmpty是自己实现的

class MySet(val helperSet: HashSet) : Set by helperSet {

fun hello() = println(“hello”)

//演示,

override fun isEmpty(): Boolean {

return true

}

}

  1. 属性委托

将一个属性的具体实现委托给另一个类去完成.

8. 泛型高级特性


8.1 泛型实化

Kotlin有内联函数,而内联函数是提替换到被调用的地方,所以不存在泛型擦除(泛型对于类型的约束只在编译期存在)问题.

泛型实化书写,首先得是内联函数,其次得加reified关键字,然后可以在函数内获取当前指定泛型的实际类型

inline fun getGenericType() = T::class.java

val result1 = getGenericType()

val result2 = getGenericType()

9. 协程


线程需要依靠操作系统的调度才能实现不同线程之间的切换.而协程可以在编程语言的层面实现不同协程之间的切换,从而大大提升并发编程的运行效率.

协程允许在单线程模式下模拟多线程编程的效果,代码执行时的挂起与恢复完全是由编程语言来控制,和操作系统无关.

  • Kotlin for Java的协程并不属于广义的协程,而是一个线程框架

  • 可以用看起来同步的代码写出实质上异步的操作

  • suspend并不是拿来切线程的,而是用来做标记和提醒的,调用的时候需要放协程里面才行.

  • 协程是怎么切线程的:看Kotlin编译成的class对应的Java代码发现,其实就是将代码分块,某一块代码执行在1个线程,另一块代码执行在另一个线程中.在编译的时候就搞了这样的操作.

9.1 创建协程作用域

GlobalScope.launch可以创建一个协程的作用域,传递给launch函数的代码块(Lambda表达式)就是在协程中运行的.

GlobalScope.launch {

println(“codes run is coroutine scope”)

//这里不是主线程 DefaultDispatcher-worker-1

println(Thread.currentThread().name)

}

GlobalScope.launch创建的是顶层协程,当应用程序结束时也会跟着结束.

可以在协程中加入delay()函数,delay()函数可以让当前协程延迟指定时间后再运行.

delay是非阻塞式的挂起函数,它只会挂起当前协程.而Thread.sleep()会阻塞当前的线程,该线程的所有协程都会被阻塞.

GlobalScope.launch {

println(“codes run is coroutine scope”)

//这里不是主线程

println(Thread.currentThread().name)

delay(1000)

println(“延迟之后的输出”)

}

runBlocking也能创建一个协程的作用域,它可以保证在协程作用域内的所有代码和子协程没有全部执行完之前一直阻塞当前线程.runBlocking函数通常只应该在测试环境下使用,在正式环境中容易产生性能上的问题.

9.2 创建多个协程

fun main() {

//创建多个协程

runBlocking {

launch {

println(“launch1 ${Thread.currentThread().name}”)

delay(1000)

println(“launch1 finished”)

}

launch {

println(“launch2 ${Thread.currentThread().name}”)

delay(1000)

println(“launch2 finished”)

}

}

}

这里的launch函数和刚才的GlobalScope.launch不一样,这个launch只能在协程的作用域下面调用,且会创建一个子协程.子协程的特点是如果外层作用域的协程结束了,那么该作用域下的所有子协程也会一同结束.

上面的输出如下:

launch1 main

launch2 main

launch1 finished

launch2 finished

日志是交叉打印的,很明显,这是并发执行的.但是线程却是相同的线程.这里由编程语言来决定如何在多个协程之间进行调度,让谁挂起,让谁运行.调度过程不需要操作系统参与,这使得协程并发效率出奇得高.

9.3 suspend 挂起

当需要将部分代码提取到一个单独的函数中,这个函数是没有协程作用域的.Kotlin提供一个suspend关键字,使用它可以将任意函数声明成挂起函数,挂起函数之间是可以互相调用的.

suspend只能声明挂起函数,而不能提供协程作用域,在里面调用launch(必须在协程作用域调用才行)是不得行的.要想有协程作用域,可以使用coroutineScope.

coroutineScope也是一个挂起函数,因此可以在其他任何挂起函数中调用.coroutineScope会继承外部的协程作用域并创建一个子作用域. 于是可以这样用:

suspend fun printDot() {

coroutineScope {

launch {

println(“.”)

delay(1000)

println(“延迟之后的输出”)

}

}

}

coroutineScope有点类似runBlocking,保证其作用域内的所有代码和子线程全部执行完之前,会一直阻塞当前协程.

但是runBlocking会阻塞当前线程,影响较大.而coroutineScope只会阻塞当前协程,不会影响其他协程,也不会影响其他线程.

可创建新的协程作用域:

  • GlobalScope.launch 可在任何地方调用

  • runBlocking 可在任何地方调用

  • lanuch

  • coruotineScope

9.4 更多的作用域构建器

runBlocking会阻塞线程,只能在测试环境下使用.而GlobalScope.launch是顶层协程,比如在Activity中使用来请求网络,还没请求回来的时候,Activity已关闭,这时需要手动管理(去取消)这个顶层协程,比较麻烦. 调用下面的代码会取消顶层协程.

val job = GlobalScope.launch { }

job.cancel()

但是实际项目中,一般会用CoroutineScope

val job = Job()

//返回的是CoroutineScope对象 这里是调用的CoroutineScope方法

val scope = CoroutineScope(job)

scope.launch {

}

所有使用CoroutineScope对象的launch创建的协程统统会被job所管理(都是在它的作用域下面).大大降低协程维护成本.

9.5 创建协程,并获取其执行结果

使用async函数,就可以获取协程的执行结果.它会创建一个子协程,并返回Deferred对象,然后我们调用其await方法即可知道结果.下面是简单计算一下5+5

runBlocking {

val result = async {

delay(100)

5 + 5

}.await()

println(result)

}

注意,调用await方法之后会阻塞当前协程,直到子协程拿到结果,才会执行后面的代码(对应上面是println语句).为了提高效率,可以先拿到返回Deferred对象,最后需要结果的时候才调用await方法

runBlocking {

val start = System.currentTimeMillis()

val deferred1 = async {

delay(1000)

5 + 5

}

val deferred2 = async {

delay(1000)

6 + 6

}

println(“结果是 ${deferred1.await() + deferred2.await()}”)

val end = System.currentTimeMillis()

println(“花费时间: ${end - start}”)

}

9.6 withContext

withContext大致是async函数的简化版,它是一个挂起函数,返回结果是withContext函数体内最后一行代码.相当于val result = async{5+5}.await()

runBlocking {

val result = withContext(Dispatchers.Default) {

5 + 5

}

println(result)

}

调用withContext函数后,函数体内的代码会被立即执行,同时需要指定一个线程参数.这个参数有如下几个值:

  • Dispatchers.Default 会开启子线程,并使用一种较低并发的线程策略.适合计算密集型任务.

  • Dispatchers.IO 会开启子线程,并使用一种较高并发的线程策略.网络请求比较合适

  • Dispatchers.Main 不会开启子线程,而是在Android主线程执行代码.

9.7 使用协程简化回调

suspendCoroutine 函数可以将当前协程立即挂起,然后在一个普通的线程执行lambda表达式中的代码.Lambda表达式的参数是一个Continuation参数,调用它的resume方法或resumeWithException可以让协程恢复执行.

来看一段代码:

suspend fun request(address: String): String {

return suspendCoroutine { continuation ->

HttpUtil.sendHttpRequest(address, object : HttpCallbackListener {

override fun onFinish(response: String) {

continuation.resume(response)

}

override fun onError(e: Exception) {

continuation.resumeWithException(e)

}

})

}

}

GlobalScope.launch {

val response = request(“https://www.baidu.com/”)

Log.d(“xfhy”, “网络请求结果 : $response”)

}

将网络请求的代码用suspendCoroutine包装一下,免得每次去手动生成一个匿名类,然后在里面拿到结果的时候调用continuation的resume方法将结果返回,这样在外面即可拿到结果. 使用request方法请求网络,只需要写一句代码即可.上面为了实例,没有加try…catch.

10. Android系统架构


JK14sg.png

Linux内核

Android平台的基础是Linux内核.

硬件抽象层(HAL)

硬件抽象层提供标准界面,向更高级别的Java API框架显示设备硬件功能.

Android Runtime

对于运行Android 5.0(API 21) 或更高版本的设备,每个应用都在棋自己的进程中运行,并且有其自己的Android Runtime(ART)实例.

原生C/C++库

许多核心Android系统组件和服务(例如ART和HAL)构建自原生代码,需要以C和C++编写的原生库.

Java API 框架

可通过以Java语言编写的API使用Android OS 的整个功能集.

系统应用

Android随附一套用于电子邮件,短信,日历,互联网浏览和联系人等的核心应用.

11. Jetpack


Jetpack是一个开发者组件工具集,主要目的是帮助我们写出更加简洁的代码,简化开发过程.Jetpack中的组件,大部分不依赖任何Android系统版本,这些组件通常定义在AndroidX库中,并且拥有非常好的向下兼容性.

Jetpack官网地址

11.1 ViewModel

ViewModel官网地址

ViewModel是用来专门存放于界面相关数据的,尽量将数据存放到ViewModel中,减少Activity的逻辑. ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续存在。下面是ViewModel的生命周期

ViewModel 使用及原理解析

11.2 Lifecycles

让任何类都能轻松感知到Activity的生命周期.

Lifecycle 使用及原理解析 一文搞懂

11.3 LiveData

LiveData是Jetpack提供的一种响应式编程组件,它可以包含任何类型的数据,并在数据发生变化的时候通知给观察者. LiveData是Activity与ViewModel之间通信的桥梁,它内部靠的是Lifecycles组件来自我感知生命周期的变化,从而在Activity销毁的时候及时释放引用,避免产生内存泄露.

LiveData 使用及原理解析

11.4 Room

Android官网的ORM框架(对象关系映射).

11.4.1 Entity

定义封装实际数据的实体类,每个视图类都会在数据库中有一张对应的表,并且表中的列是根据实体类中的字段自动生成的.

11.4.2 Dao

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

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

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

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

droid开发面试专题资料**,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

[外链图片转存中…(img-YPEEWNte-1714678991888)]

【算法合集】

[外链图片转存中…(img-IDQ7kLNY-1714678991889)]

【延伸Android必备知识点】

[外链图片转存中…(img-3BBDTC6q-1714678991889)]

【Android部分高级架构视频学习资源】

Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值