Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
CharonChui committed Apr 9, 2024
1 parent 252a6aa commit 26bdff7
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 34 deletions.
37 changes: 37 additions & 0 deletions AdavancedPart/AOP.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,41 @@ AOP(Aspect Oriented Programing),面向切面编程。
而AOP,就是将各个模块中的通用逻辑抽离出来。
我们将这些逻辑视为Aspect(切面),然后动态地把代码插入到类的指定方法、指定位置中。

一句话概括: 在运行时,动态的将代码切入到类的指定方法、指定位置上的编程思想就是面相切面的编程。


一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。


### AOP的实现方式

#### 静态AOP

在编译器,切面直接以字节码的形式编译到目标字节码文件中。

1. AspectJ
AspectJ属于静态AOP,它是在编译时进行增强,会在编译时期将AOP逻辑织入到代码中。

由于是在编译器织入,所以它的优点是不影响运行时性能,缺点是不够灵活。

2. AbstractProcessor
自定义一个AbstractProcessor,在编译期去解析编译的类,并且根据需求生成一个实现了特定接口的子类(代理类)

#### 动态AOP
1. JDK动态代理
通过实现InvocationHandler接口,可以实现对一个类的动态代理,通过动态代理可以生成代理类,从而在代理类方法中,在执行被代理类方法前后,添加自己的实现内容,从而实现AOP。

2. 动态字节码生成
在运行期,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中,没有接口也可以织入,但扩展类的实例方法为final时,则无法进行织入。比如Cglib

CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。

3. 自定义类加载器
在运行期,目标加载前,将切面逻辑加到目标字节码里。如:Javassist

Javassist是可以动态编辑Java字节码的类库。它可以在Java程序运行时定义一个新的类,并加载到JVM中;还可以在JVM加载时修改一个类文件。

4. ASM
ASM可以在编译期直接修改编译出的字节码文件,也可以像Javassit一样,在运行期,类文件加载前,去修改字节码。


2 changes: 1 addition & 1 deletion AdavancedPart/屏幕适配之百分比方案详解.md
Original file line number Diff line number Diff line change
Expand Up @@ -557,4 +557,4 @@ public void restoreLayoutParams(ViewGroup.LayoutParams params) {
---

- 邮箱 :charon.chui@gmail.com
- Good Luck!
- Good Luck!
7 changes: 6 additions & 1 deletion Gradle&Maven/Gradle专题.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ Gradle专题
作用
---

[Gradle](https://docs.gradle.org/7.3.3/userguide/what_is_gradle.html)是一个开源的自动化构建工具。现在Android项目构建编译都是通过Gradle进行的,Gradle的版本在`gradle/wrapper/gradle-wrapper.properties`下:
[Gradle](https://docs.gradle.org/7.3.3/userguide/what_is_gradle.html)是一个开源的自动化构建工具。现在Android项目构建编译都是通过Gradle进行的。

Gradle的版本在`gradle/wrapper/gradle-wrapper.properties`下:
![image](https://github.com/CharonChui/Pictures/blob/master/gradle_version.png?raw=true)

当前Gradle版本为6.7.1。当我们执行assembleDebug/assembleRelease编译命令的时候,Gradle就会开始进行编译构建流程。


gradle-wrapper是对Gradle的一层包装,便于在团队开发过程中统一Gradle构建的版本号,这样大家都可以使用统一的Gradle版本进行构建。
里面的distributionUrl属性是用于配置Gradle发行版压缩包的下载地址。

简介
---

Expand Down
Binary file added KotlinCourse/.8.Kotlin_协程.md.swp
Binary file not shown.
14 changes: 14 additions & 0 deletions KotlinCourse/1.Kotlin_简介&变量&类&接口.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,20 @@ private var lazyValue: Fragment? = null
当您稍后需要在代码中初始化var时,请选择lateinit,它将被重新分配。当您想要初始化一个val值一次时,特别是当初始化的计算量很大时,请选择by lazy。
```kotlin
val name: String by lazy {getName()}
```
这样,当第一次使用name引用时,getName()函数只会被调用一次。此外,还可以使用函数引用代替lambda表达式:
```kotlin
val name: String by lazy(::getName)
fun getName() : String {
println("computing name")
return "Mockey"
}
```
## 类的定义:使用`class`关键字
Expand Down
78 changes: 46 additions & 32 deletions KotlinCourse/8.Kotlin_协程.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@ Kotlin引入了协程(Coroutine)来支持更好的异步操作,利用它

## 起源

协程是一个无优先级的子程序调用组件,允许子程序在特定的地方挂起恢复。线程包含于进程,协程包含于线程。只要内存足够,
一个线程中可以有任意多个协程,但某一时刻只能有一个协程在运行,多个协程分享该线程分配到的计算机资源。

线程是由操作系统来进行调度的,当操作系统切换线程的时候,会产生一定的消耗。而协程不一样,协程是包含于线程的,也就是说协程
是工作在线程之上的,协程的切换可以由程序自己来控制,不需要操作系统进行调度。这样的话就大大降低了开销。



协程就像一个轻量级的线程在幕后,启动协程就像启动一个单独的执行线程。线程在其他语言中很常见,例如Java,协程和线程可以并行运行,并互相通信。然而,不同点在于使用协程比使用线程更加高效。在性能方面,启动一个线程并使其保持运行是非常昂贵的。处理器通常只能同时运行有限数量的线程,并且运行尽可能少的线程会更高效。而另一方面,协程默认运行在共享的线程池中,同一个线程可以运行多个协程。由于使用的线程较少,当你想要运行异步任务时,使用协程会更加高效。
协程就像一个轻量级的线程在幕后,启动协程就像启动一个单独的执行线程。线程在其他语言中很常见,例如Java,协程和线程可以并行运行,并互相通信。然而,不同点在于使用协程比使用线程更加高效。在性能方面,启动一个线程并使其保持运行是非常昂贵的。

处理器通常只能同时运行有限数量的线程,并且运行尽可能少的线程会更高效。

而另一方面,协程默认运行在共享的线程池中,同一个线程可以运行多个协程。由于使用的线程较少,当你想要运行异步任务时,使用协程会更加高效。

**也就是说本质上Kotlin协程就是创建了一个可以复用的线程池,并且协程的delay是一个特殊的挂起函数,它不会造成线程堵塞,但是会挂起协程,并且只能在协程中使用。**

协程是语言层面的东西,线程是系统层面的东西。
协程就是一段代码块,既然是代码那就离不开CPU的执行,而CPU调度的基本单位是线程。


## 进程、线程、协程
进程:一段程序的执行过程,资源分配和调度的基本单位,有其独立地址空间,互相之间不发生干扰
Expand All @@ -33,7 +40,15 @@ CPU增加内存管理单元,进行虚拟地址和物理地址的转换

进程是一个实体,包括程序代码以及其相关资源(内存,I/O,文件等),可被操作系统调度。但想一边操作I/O进行输入输出,一边想进行加减计算,就得两个进程,这样写代码,内存就爆表了。于是又想着能否有一轻量级进程呢,只执行程序,不需要独立的内存,I/O等资源,而是共享已有资源,于是产生了线程。

一个进程可以跑很多个线程处理并发,但是线程进行切换的时候,操作系统会产生中断,线程会切换到相应的内核态,并进行上下文的保存,这个过程不受上层控制,是操作系统进行管理。然而内核态线程会产生性能消耗,因此线程过多,并不一定提升程序执行的效率。正是由于1.线程的调度不能精确控制;2.线程的切换会产生性能消耗。协程出现了。
一个进程可以跑很多个线程处理并发,但是线程进行切换的时候,操作系统会产生中断,线程会切换到相应的内核态,并进行上下文的保存,这个过程不受上层控制,是操作系统进行管理。
然而内核态线程会产生性能消耗,因此线程过多,并不一定提升程序执行的效率。

正是由于:

1. 线程的调度不能精确控制;
2. 线程的切换会产生性能消耗。

协程出现了。

协程:

Expand All @@ -43,17 +58,30 @@ CPU增加内存管理单元,进行虚拟地址和物理地址的转换
4. 协程是非抢占式调度,当前协程切换到其他协程是由自己控制;线程则是时间片用完抢占时间片调度

优点:

1. 用户态,语言级别
2. 无切换性能消耗
3. 非抢占式
4. 同步代码思维
5. 减少同步锁

缺点:

1. 注意全局变量
2. 阻塞操作会导致整个线程被阻塞


用一句话概括Kotlin Couroutine的特点即是"以同步之名,行异步之实".

简单地讲,Kotlin 的协程就是一个封装在线程上面的线程框架。

它有两个非常关键的亮点:

- 耗时函数自动后台,从而提高性能;
- 线程的「自动切回」

所以,Kotlin 的协程在 Android 开发上的核心好处就是:消除回调地域。


## 使用

如需在 Android 项目中使用协程,请将以下依赖项添加到应用的build.gradle文件中:
Expand Down Expand Up @@ -400,7 +428,6 @@ main: Now I can quit.
对于回调式的写法,如果并发场景再复杂一些,代码的嵌套可能会更多,这样的话维护起来就非常麻烦。但如果你使用了 Kotlin 协程,多层网络请求只需要这么写:
```
🏝️
coroutineScope.launch(Dispatchers.Main) { // 开始协程:主线程
val token = api.getToken() // 网络请求:IO 线程
val user = api.getUser(token) // 网络请求:IO 线程
Expand All @@ -413,8 +440,6 @@ coroutineScope.launch(Dispatchers.Main) { // 开始协程:主线程
协程最简单的使用方法,其实在前面章节就已经看到了。我们可以通过一个 `launch` 函数实现线程切换的功能:
```
🏝️
// 👇
coroutineScope.launch(Dispatchers.IO) {
...
}
Expand All @@ -426,45 +451,38 @@ coroutineScope.launch(Dispatchers.IO) {
所以,什么时候用协程?当你需要切线程或者指定线程的时候。你要在后台执行任务?切!
```
🏝️
launch(Dispatchers.IO) {
val image = getImage(imageId)
}
复制代码
```
然后需要在前台更新界面?再切!
```
🏝️
coroutineScope.launch(Dispatchers.IO) {
val image = getImage(imageId)
launch(Dispatch.Main) {
avatarIv.setImageBitmap(image)
}
}
复制代码
```
好像有点不对劲?这不还是有嵌套嘛。
如果只是使用 `launch` 函数,协程并不能比线程做更多的事。不过协程中却有一个很实用的函数:`withContext` 。这个函数可以切换到指定的线程,并在闭包内的逻辑执行结束之后,自动把线程切回去继续执行。那么可以将上面的代码写成这样:
```
🏝️
coroutineScope.launch(Dispatchers.Main) { // 👈 在 UI 线程开始
val image = withContext(Dispatchers.IO) { // 👈 切换到 IO 线程,并在执行完成后切回 UI 线程
getImage(imageId) // 👈 将会运行在 IO 线程
}
avatarIv.setImageBitmap(image) // 👈 回到 UI 线程更新 UI
}
复制代码
```
这种写法看上去好像和刚才那种区别不大,但如果你需要频繁地进行线程切换,这种写法的优势就会体现出来。可以参考下面的对比:
```
🏝️
// 第一种写法
coroutineScope.launch(Dispachers.IO) {
...
Expand All @@ -491,13 +509,11 @@ coroutineScope.launch(Dispachers.Main) {
}
...
}
复制代码
```
由于可以"自动切回来",消除了并发代码在协作时的嵌套。由于消除了嵌套关系,我们甚至可以把 `withContext` 放进一个单独的函数里面:
```
🏝️
launch(Dispachers.Main) { // 👈 在 UI 线程开始
val image = getImage(imageId)
avatarIv.setImageBitmap(image) // 👈 执行结束后,自动切换回 UI 线程
Expand All @@ -506,30 +522,21 @@ launch(Dispachers.Main) { // 👈 在 UI 线程开始
fun getImage(imageId: Int) = withContext(Dispatchers.IO) {
...
}
复制代码
```
这就是之前说的「用同步的方式写异步的代码」了。
不过如果只是这样写,编译器是会报错的:
```
🏝️
fun getImage(imageId: Int) = withContext(Dispatchers.IO) {
// IDE 报错 Suspend function'withContext' should be called only from a coroutine or another suspend funcion
}
复制代码
```
意思是说,`withContext` 是一个 `suspend` 函数,它需要在协程或者是另一个 `suspend` 函数中调用。
#### 挂起函数
当我们调用标记有特殊修饰符`suspend`的函数时,会发生挂起:
Expand All @@ -539,9 +546,13 @@ suspend fun doSomething(foo: Foo): Bar {
……
}
```
这样的函数称为挂起函数,因为调用它们可能挂起协程(如果相关调用的结果已经可用,库可以决定继续进行而不挂起)。挂起函数能够以与普通函数相同的方式
获取参数和返回值,但它们只能从协程和其他挂起函数中调用。事实上,要启动协程,
必须至少有一个挂起函数,它通常是匿名的(即它是一个挂起`lambda`表达式)。让我们来看一个例子,一个简化的`async()`函数
这样的函数称为挂起函数,因为调用它们可能挂起协程(如果相关调用的结果已经可用,库可以决定继续进行而不挂起)。
挂起函数能够以与普通函数相同的方式获取参数和返回值,但它们只能从协程和其他挂起函数中调用。
事实上,要启动协程,必须至少有一个挂起函数,它通常是匿名的(即它是一个挂起`lambda`表达式)。
让我们来看一个例子,一个简化的`async()`函数
(源自`kotlinx.coroutines`库):
```kotlin
Expand All @@ -558,7 +569,8 @@ async {
}
```
`await()`可以是一个挂起函数(因此也可以在一个`async {}`块中调用),该函数挂起一个协程,直到一些计算完成并返回其结果:
`await()`可以是一个挂起函数(因此也可以在一个`async {}`块中调用),该函数挂起一个协程,直到一些计算完成并返回其结果:
```kotlin
async {
……
Expand All @@ -569,13 +581,15 @@ async {
```
请注意,挂起函数`await()`和`doSomething()`不能在像`main()`这样的普通函数中调用:
请注意,挂起函数`await()`和`doSomething()`不能在像`main()`这样的普通函数中调用:
```kotlin
fun main(args: Array<String>) {
doSomething() // 错误:挂起函数从非协程上下文调用
}
```
还要注意的是,挂起函数可以是虚拟的,当覆盖它们时,必须指定`suspend`修饰符:
```kotlin
interface Base {
suspend fun foo()
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Android学习笔记
- [1.音视频基础知识][328]
- [2.系统播放器MediaPlayer][329]
- [11.播放器组件封装][330]
- [MediaMetadataRetriever][344]
- [DNS及HTTPDNS][23]
- [流媒体协议][224]
- [流媒体协议][246]
Expand Down Expand Up @@ -721,6 +722,8 @@ Android学习笔记
[341]: https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/%E8%A7%86%E9%A2%91%E5%B0%81%E8%A3%85%E6%A0%BC%E5%BC%8F/AVI.md "AVI"
[342]: https://github.com/CharonChui/AndroidNote/tree/master/VideoDevelopment/OpenCV "OpenCV"
[343]: https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenCV/1.OpenCV%E7%AE%80%E4%BB%8B.md "1.OpenCV简介"
[344]: "MediaMetadataRetriever"



Developed By
Expand Down
55 changes: 55 additions & 0 deletions SourceAnalysis/ARouter解析.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ARouter解析

[ARouter](https://github.com/alibaba/ARouter)

> 一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦
简单的说: 它是一个路由系统 ——— 给无依赖的组件提供通信和路由的能力。

举个例子:
你过节了你想写一个明信片递给远方的朋友,那你就需要通过邮局(ARoter)来把明信片派送给你的朋友(你和你的朋友相当于两个组件)。

使用ARouter在进行Activity跳转非常简单:

- 初始化ARouter `ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化`
- 添加注解@Route
```java
// 在支持路由的页面上添加注解(必选)
// 这里的路径需要注意的是至少需要有两级,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
...
}
```
- 发起路由 `ARouter.getInstance().build("/test/activity").navigation();`



ARouter框架能将多个服务提供者隔离,减少相互之间的依赖。其实现的流程和我们平常的快递物流管理很类似,每一个具体的快递包裹就是一个独立的服务提供者(IProvider),每一个快递信息单就是一个RouteMeta对象,客户端就是快递的接收方,而使用@Route注解中的path就是快递单号。在初始化流程中,主要完成的工作就是将所有注册的快递信息表都在物流中心(LogisticsCenter)注册,并将数据存储到数据仓库中(Warehouse)。

作者:魔焰之
链接:https://www.jianshu.com/p/11006054f156
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


















---

- 邮箱 :charon.chui@gmail.com
- Good Luck!
Loading

0 comments on commit 26bdff7

Please sign in to comment.