最后
文章不易,如果大家喜欢这篇文章,或者对你有帮助希望大家多多点赞转发关注哦。文章会持续更新的。绝对干货!!!
- Android进阶学习全套手册
关于实战,我想每一个做开发的都有话要说,对于小白而言,缺乏实战经验是通病,那么除了在实际工作过程当中,我们如何去更了解实战方面的内容呢?实际上,我们很有必要去看一些实战相关的电子书。目前,我手头上整理到的电子书还算比较全面,HTTP、自定义view、c++、MVP、Android源码设计模式、Android开发艺术探索、Java并发编程的艺术、Android基于Glide的二次封装、Android内存优化——常见内存泄露及优化方案、.Java编程思想 (第4版)等高级技术都囊括其中。
-
Android高级架构师进阶知识体系图
关于视频这块,我也是自己搜集了一些,都按照Android学习路线做了一个分类。按照Android学习路线一共有八个模块,其中视频都有对应,就是为了帮助大家系统的学习。接下来看一下导图和对应系统视频吧!!!
-
Android对标阿里P7学习视频
- BATJ大厂Android高频面试题
这个题库内容是比较多的,除了一些流行的热门技术面试题,如Kotlin,数据库,Java虚拟机面试题,数组,Framework ,混合跨平台开发,等
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
return true
}
}
- 属性委托
将一个属性的具体实现委托给另一个类去完成.
8.1 泛型实化
Kotlin有内联函数,而内联函数是提替换到被调用的地方,所以不存在泛型擦除(泛型对于类型的约束只在编译期存在)问题.
泛型实化书写,首先得是内联函数,其次得加reified关键字,然后可以在函数内获取当前指定泛型的实际类型
inline fun getGenericType() = T::class.java
val result1 = getGenericType()
val result2 = getGenericType()
线程需要依靠操作系统的调度才能实现不同线程之间的切换.而协程可以在编程语言的层面实现不同协程之间的切换,从而大大提升并发编程的运行效率.
协程允许在单线程模式下模拟多线程编程的效果,代码执行时的挂起与恢复完全是由编程语言来控制,和操作系统无关.
-
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.
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随附一套用于电子邮件,短信,日历,互联网浏览和联系人等的核心应用.
Jetpack是一个开发者组件工具集,主要目的是帮助我们写出更加简洁的代码,简化开发过程.Jetpack中的组件,大部分不依赖任何Android系统版本,这些组件通常定义在AndroidX库中,并且拥有非常好的向下兼容性.
11.1 ViewModel
ViewModel是用来专门存放于界面相关数据的,尽量将数据存放到ViewModel中,减少Activity的逻辑. ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续存在。下面是ViewModel的生命周期
11.2 Lifecycles
让任何类都能轻松感知到Activity的生命周期.
11.3 LiveData
LiveData是Jetpack提供的一种响应式编程组件,它可以包含任何类型的数据,并在数据发生变化的时候通知给观察者. LiveData是Activity与ViewModel之间通信的桥梁,它内部靠的是Lifecycles组件来自我感知生命周期的变化,从而在Activity销毁的时候及时释放引用,避免产生内存泄露.
11.4 Room
Android官网的ORM框架(对象关系映射).
11.4.1 Entity
定义封装实际数据的实体类,每个视图类都会在数据库中有一张对应的表,并且表中的列是根据实体类中的字段自动生成的.
11.4.2 Dao
数据访问对象,通常会在这里对数据库的各项操作进行封装.
11.4.3 Database
用于定义数据库中的关键信息,包括数据库的版本号,把汗哪些实体类以及提供D奥层的访问实例
11.5 WorkManager
官方推出WorkManager用于处理一些要求定时执行任务的地方,它可以根据操作系统版本自动选择使用AlarmManager实现还是JobScheduler.
WorkManager注册的周期性任务不能保证一定准时执行,这是为了系统减少电量消耗,可能会将出发时间临近的几个任务放在一起执行,这样可大幅度减少CPU被唤醒的次数,从而有效延长电池的使用时间.
基本用法:
-
定义一个后台任务,并实现具体的任务逻辑
-
配置该后台任务的运行条件和约束信息,并构建后台任务请求
-
将该后台任务请求传入WokManager的enqueue()方法中,系统会在合适的时间运行.
-
先注册一个bintray账号.网址是
https://bintray.com
-
然后在我的首页,点击
Add New Repository
创建一个新的仓库.仓库类型选择Maven
,开源许可随便选,可以是Apache-2.0
-
回到我们编写的库中,在项目的build.gradle中引入
bintray-release
buildscript {
dependencies {
classpath ‘com.novoda:bintray-release:0.9.1’
}
}
- 然后在开源库Library的build.gradle中填写如下配置
apply plugin: ‘com.novoda.bintray-release’
publish {
userOrg = ‘xfhy’//bintray.com用户名
groupId = ‘com.permissionx.xfhy’//jcenter上的路径
artifactId = ‘permissionx’//项目名称
repoName = “permissionx”
publishVersion = ‘1.0.0’//版本号
desc = ‘Make Android runtime permission request easy’//描述,不重要
website = ‘https://github.com/xfhy/PermissionX’//网站,不重要
}
总结
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的14套腾讯、字节跳动、阿里、百度等2021最新面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
lishVersion = ‘1.0.0’//版本号
desc = ‘Make Android runtime permission request easy’//描述,不重要
website = ‘https://github.com/xfhy/PermissionX’//网站,不重要
}
总结
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的14套腾讯、字节跳动、阿里、百度等2021最新面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。
[外链图片转存中…(img-r2Fxrv5T-1715796750568)]
[外链图片转存中…(img-EbDPbWc4-1715796750569)]
[外链图片转存中…(img-a4SPO39q-1715796750569)]
[外链图片转存中…(img-Cxe0ASMx-1715796750569)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!