Android Kotlin协程实战

news2024/11/20 3:32:16

你能听懂的Kotlin协程课,跟老司机学,不用自己瞎折腾

认识协程

协程难在哪儿?

  • Ja v a中不曾出现的,新概念
  • 概念不清晰,我们看到的大都是不同语言对于协程的实现或者衍生
  • Kotlin 基础不扎实
  • 多线程编程基础太薄弱

协程是什么?

协程基于线程,它是轻量级线程。

在An dr oid 中协程用来解决什么问题?

  • 处理耗时任务,这种任务常常会阻塞主线程。
  • 保 证 主线 程 安 全 , 即 确 保 安 全 地 从 主线 程 调 用 任 何 s u s p e n d 函 数 。

异 步任 务

在这里插入图片描述

使用协程

在这里插入图片描述

协程是什么?

  • 协程让异步逻辑同步化,杜绝回调地狱。
  • 协程最核心的点就是,函数或者一段程序能够被挂起,稍后再在挂起的位 置恢复。

协 程的挂起与恢复

常规函数基础操作包括:invoke (或call)和return,协程新增了suspend和resume:
• suspend—也称为挂起或暂停,用于暂停执行当前协程,并保存所有局部变量;
• resume—用于让已暂停的协程从其暂停处继续执行。

堆栈帧中的函数调用流程

在这里插入图片描述

挂起函数

  • 使用suspen d关键字修饰的函数叫作挂起函数。
  • 挂起函数只能在协程体内或其他挂起函数内调用。

调度器

在这里插入图片描述

协程的两部分

Kotlin的协程实现分为两个层次:
• 基础设施层,标准库的协程API,主要对协程提供了概念和语义上最基本的支持
• 业务框架层,协程的上层框架支

任 务泄 漏

  • 当某个协程任务丢失,无法追踪,会导致内存、CPU、磁盘等资源浪费,甚至发 送一个无用的网络请求,这种情况称为任务泄漏。
  • 为了能够避免协程泄漏,Kotlin引入了结构化并发机制。

结构化并发

使用结构化并发可以做到:
• 取消任务,当某项任务不再需要时取消它。
• 追踪任务,当任务正在执行是,追踪它。
• 发出错误信号,当协程失败时,发出错误信号表明有错误发生

CoroutineScope

  • 定义协程必须指定其CoroutineScope,它会跟踪所有协程,同样它还可以取消
    由它所启动的所有协程。
  • 常用的相关API有:
    • Globalscope,生命周期是pr ocess级别的,即使Activity或Fragment已经被销毁,协程仍然在执行。 • MainSc ope,在Activity中使用,可以在onDestroy(中取消协程。
    • viewModelScope,只能在ViewModel中使用,绑定ViewModel的生命周期。
    • lifecycleScope,只能在Activity、Fragment中使用,会绑定Activity和Fragment的生命周期。

启动协程

协 程构 建 器

  • launch与async构建器都用来启动新协程
    • launch,返回一个Job并且不附带任何结果值。
    • async,返回一个Deferred, Deferred也是一个Job,可以使用.await(在一个延期的值 上得到它的最终结果。
  • 等待一个作业 • joinSawait
    • 组合并发

协 程的启动 模式

DEFAULT:协程创建后,立即开始调度,在调度前如果协程被取消,其将直接进入取消 响应的状态。
ATOMIC:协程创建后,立即开始调度,协程执行到第一个挂起点之前不响应取消。
LAZY:只有协程被需要时,包括主动调用协程的start、join或者await等函数时才会开始
调度,如果调度前就被取消,那么该协程将直接进入异常结束状态。
UNDISPATCHED:协程创建后立即在当前函数调用栈中执行,直到遇到第一个真正挂起 的点

协 程的作用域构建器

coroutineScope-SrunBlocking
• runBlocking是常规函数,而coroutineScope是挂起函数。
• 它们都会等待其协程体以及所有子协程结束,主要区别在于runBlocking方法会阻塞当
前 线 程 来 等 待 , 而 c o r o u t i n e S c o p e 只 是 挂 起 , 会释 放 底 层 线 程 用 于其 他 用 途 。

协 程的作用域构建器

coroutineScope-supervisorScope
• coroutineScope:一个协程失败了,所有其他兄弟协程也会被取消。
• supervisorScope:一个协程失败了,不会影响其他兄弟协程。

J ob对象

对 于 每 一 个 创 建 的 协 程 (通 过 l a u n c h 或 者 a s y n c ) , 会 返 回 一 个 J o b 实 例 , 该 实 例 是 协 程
的唯一标示,并且负责管理协程的生命周期。

一个任务可以包含一系列状态:新创建(New)、活跃(Active)、完成中(Completi
ng)、已完成 (Completed)、取消中 (Cancelling)和已取消 (Cancelled)。虽然 我们无法直接访问这些状态,但是我们可以访问J o b 的属性:i s Ac t i v e 、i s Ca n ce l l e d 和i s
Completed.

J ob的生命周期

如 果 协 程 处 于活 跃 状 态 , 协 程 运 行 出 错 或 者 调 用 j o b . c a n c e l ()都 会 将 当 前 任 务 置 为 取 消 中 (C a n c e l l i n g ) 状 态 (i s A c t i v e = f a l s e , i s C a n c e l l e d = t r u e )。 当 所 有 的 子 协 程 都 完 成 后 , 协 程 会 进 入 已 取 消 (Cancelled)状态,此时isCompleted= true。
在这里插入图片描述

取消协程

协程的取消

取消作用域会取消它的子协程。 >被取消的子协程并不会影响其余兄弟协程。
协程通过抛出一个特殊的异常Cancell ationException 来处理取消操作。
所 有 k o t l i n x . c o r o u t i n e s 中 的 挂 起 函 数 (w i t h C o n t e x t 、 d e l a y 等 ) 都 是 可 取 消 的 。

C P U密集型任务取消

isActive是一个可以被使用在CoroutineScope中的扩展属性,检查Job是否处于活跃状态。 > ensureActive(),如果job处于非活跃状态,这个方法会立即抛出异常。
yield函数会检查所在协程的状态,如果已经取消,则抛出Cancellati onExcepti on予以响
应。此外,它还会尝试出让线程的执行权,给其他协程提供执行机会。

协程取消的副作用

在 f i n a l l y 中释 放 资 源 。
use函数:该函数只能被实现了Closeable的对象使用,程序结束的时候会自动调用close 方法,适合文件对象。

不能取消的任务

处于取消中状态的协程不能够挂起(运行不能取消的代码),当协程被取消后需要调用挂起函数,我们需要将清理任务的代码放置于NonCancellableCoroutineContext 中。
这样会挂起运行中的代码,并保持协程的取消中状态直到任务处理完成。

超时任务

很多情况下取消一个协程的理由是它有可能超时。
with Time out OrNull 通过返回null来进行超时操作,从而替代抛出一个异常。

协程的上下文

协程的上下文是什么?

CoroutineContext是 一组用于定义协程行为的元素。它由如下几项构成:
• Jo b:控制协程的生命周期
• Cor outineDis patc her:向合适的线程分发任务
• CoroutineName:协程的名称,调试的时候很有用 • CoroutineExceptionHandler:处理未被捕捉的异常

组 合 上下文中的元素

有时我们需要在协程上下文中定义多个元素。我们可以使用+操作符来实现。比如说,我 们可以显式指定 一个调度器来启动协程并且同时显式指定一个命名
在这里插入图片描述

协程 上下文的继承

对于新创建的协程,它的Cor outineContext会包含一个全新的Job实例,它会帮助我们 控制协程的生命周期。而剩 下的元素会从Corout ine Cont ext的父类继承,该父类可能是另外一个协程或者创建该协程的CoroutineSc ope。
在这里插入图片描述

协程 上下文的继承

最终的父级Cor outineCont ext 会内含Dispatchers.IO而不是scope对象里的Disp atchers.Mai n,因为 它被 协 程 的 构 建 器 里 的 参 数 覆 盖了。 此 外 , 注 意 一 下父 级 C o r o u t i n e C o n t e x t 里 的 J o b 是 s c o p e 对 象的Job (红色),而新的Job实例(绿色)会赋值给新的协程的CoroutineContext。

在这里插入图片描述

协程的异常处理

异常处理的必要性

当应用出现一些意外情况时,给用户提供合适的体验非常重要,一方面,目睹应
用崩溃是个很糟糕的体验,另一方面,在用户操作失败时,也必须要能给出正确 的提示信息。

异常的传播

协程构建器有两种形式:自动传播异常 (launch与actor),向用户暴露异常 (async与produce)当这些构建器用于创建 一个根协程时 (该协程不是另 一个协程 的子协程),前者这类构建器,异常会在它发生的第一时间被抛出,而后者则依
赖用户来最终消费异常,例如通过await或receive 。

非根协程的异常

其他协程所创建的协程中,产生的异常总是会被传播。
在这里插入图片描述

异常的传播特性

当一个协程由于一个异常而运行失败时,它会传播这个异常并传递给它的父级。接下来, 父级会进行下面几步操作:
• 取消它自己的子级
• 取消它自己
• 将异常传播并传递给它的父级
在这里插入图片描述

SupervisorJob

使用Su pervisorJob时,一个子协程的运行失败不会影响到其他子协程。Supervis or Job 不会传播异常给它的父级,它会让子协程自己处理异常。

这种需求常见于在作用域内定义作业的UI组件,如果任何一个UI的子作业执行失
败了,它并不总是有必要取消整个UI组件,但是如果UI组件被销毁了,由于它的 结果不再被需要了,它就有必要使所有的子作业执行失败。

supervisorScope

当作业自身执行失败的时候,所有子作业将会被全部取消。
在这里插入图片描述

异常的捕获

使用Cor outineEx cepti onHandler对协程的异常进行捕获。
以下的条件被满足时,异常就会被捕获:
• 时机:异常是被自动抛出异常的协程所抛出的(使用launch,而不是async时);
• 位置:在CoroutineScope的CoroutineContext中或在一个根协程(CoroutineScope 或者supervisorSc ope 的直接子协程)中。

A n d r oi d 中全局 异常处理

全局异常处理器可以获取到所有协程未处理的未捕获异常,不过它并不能对异常进行捕获, 虽然不能阻止程序崩溃,全局异常处理器在程序调试和异常上报等场景中仍然有非常大的
用处。
我们需要在Classpath 下面创建META-INF/services目录,并在其中创建一个名为kotlinx. coroutines.Cor outineExceptionHandler的文件,文件内容就是我们的全局异常处理器
的全类名。

取消与异常

取 消 与 异常 紧 密 相 关 , 协 程 内 部 使 用 C a n c e l l a t i o n E x c e p t i o n 来进 行 取 消 , 这 个异 常 会被 忽略。
当子协程被取消时,不会取消它的父协程。
如 果 一 个 协 程 遇 到 了C a n c e l l a t i o n E x c e p t i o n 以 外 的 异 常 , 它 将 使 用 该 异 常 取 消 它 的 父 协程。当父协程的所有子协程都结束后,异常才会被父协程处理。

常聚合

当协程的多个子协程因为异常而失败时,一般情况下取第一个异常进行处理。在 第一个异常之后发生的所有其他异常,都将被绑定到第一个异常之上。

认识Flow

如何表示多个值?

挂起函数可以异步的返回单个值,但是该如何异步返回多个计算好的值呢?

异步返回多个值的方案

集合
序列
挂起函数
Flow

Fl ow 与其他方式的区别

名为fl ow的Fl ow类型构建器函数。
f l o w {. . }构 建 块 中 的 代 码 可 以 挂 起 。
函数si mpl eFlow不再标有susp end修饰符。
流使用emit 函数发射值。
流使用col l ec t 函数收集值。
在这里插入图片描述

Fl o w 应用

在Androi d当中,文件下载是Fl ow的一个非常典型的应用。
在这里插入图片描述

冷流

Fl ow是一种类似于序列的冷流,fl ow构建器中的代码直到流被收集的时候才运行。
在这里插入图片描述

流 的连 续 性

流的每次单独收集都是按顺序执行的,除非使用特殊操作符。
从上游到下游每个过渡操作符都会处理每个发射出的值,然后再交给末端操作符。
在这里插入图片描述

流 构建 器

flowOf构建器定义了一个发射固定值集的流。
使用.asFl ow()扩展函数,可以将各种集合与序列转换为流。

在这里插入图片描述

上下文

流的收集总是在调用协程的上下文中发生,流的该属性称为上下文保存。
f l o w {. . }构 建 器 中 的 代 码 必 须 遵 循 上 下 文 保 存 属 性 , 并 且 不 允 许 从 其 他 上 下 文 中 发 射 (emit)。
flowOn操作符,该函数用于更改流发射的上下文。

启动流

使用launchl n替換collect 我们可以在单独的协程中启动流的收集

流的取消

流采用与协程同样的协作取消。像往常一样,流的收集可以是当流在一个可取消的挂起函数 (例如delay)中挂起的时候取消。
在这里插入图片描述

流的取消检测

为方便起见,流构建器对每个发射值执行附加的ensureActive 检测以进行取消,这 意 味 着 从 f l o w {… } 发 出 的 繁 忙 循 环 是 可 以 取 消 的 。
出于性能原因,大多数其他流操作不会自行执行其他取消检测,在协程处于繁忙循环的情况下,必须明确检测是否取消。
通 过 c a n c e l l a b l e 操 作 符 来执 行 此 操 作 。

背压

buffer(,并发运行流中发射元素的代码。
c o n f l a t e (), 合 并 发 射 项 , 不 对 每 个 值 进 行 处 理 。
collectLate st(),取消并重新发射最后一个值。
当必须更改Cor outineDispatcher时,flowOn操作符使用了相同的缓冲机制,但 是buffer函数显式地请求缓冲而不改变执行上下文。

操作符

过 渡流 操 作 符

可以使用操作符转换流,就像使用集合与序列一样。
过渡操作符应用于上游流,并返回下游流。
这些操作符也是冷操作符,就像流一样。这类操作符本身不是挂起函数。
它运行的速度很快,返回新的转换流的定义。

末端流操作符

末端操作符是在流上用于启动流收集的挂起函数。collect是最基础的未端操作符,但是 还有另外 一些更方便使用的末端操作符:
• 转化为各种集合,例如t oList 与t oSet 。
• 获取第一个(first)值与确保流发射单个(single)值的操作符。
• 使 用 r e d u c e 与 f o l d 将 流 规 约 到 单 个值 。

组合多个流

就像Kotlin标准库中的Sequen ce.zip扩展函数一样,流拥有一个zip操作符用于组 合两个流中的相关值。

展平流

流表示异步接收的值序列,所以很容易遇到这样的情况 :每个值都会触发对另一 个值序列的请求,然而,由于流具有异步的性质,因此需要不同的展平模式,为此,存在一系列的流展平操作符: • flatMapConcat连接模式,
• flatMapMerge 合并模式
• flatMapLatest 最新展平模式

在这里插入图片描述

异常

流的异常处理

当运算符中的发射器或代码抛出异常时,有几种处理异常的方法:
• try/catcht
• catch函数

流的完成

当流收集完成时 (普通情况或异常情况),它可能需要执行一个动作。
• 命令式finally块
• onCompletion声明式处理

Channel-通道

认识Chann el

Channel实际上是一个并发安全的队列,它可以用来连接协程,实现不同协程的 通信。
在这里插入图片描述

Channel的容量

Channel实际上就是一个队列,队列中一定存在缓冲区,那么一旦这个缓冲区满了,并且 也 一 直没 有 人 调 用 r e c e i v e 并 取 走 函 数 , s e n d 就 需 要 挂 起 。 故 意 让 接 收 端 的 节奏 放 慢 , 发 现send总是会挂起,直到re ceive之后才会继续往下执行。

迭代Chann el

Channel 本身确实像序列,所以我们在读取的时候可以直接获取一个Channel 的it erator.
在这里插入图片描述

produceSactor

构造生产者与消费者的便捷方法。
我们可以通过pr oduce 方法启动一个生产者协程,并返回一个Receiv eChann el,其他协
程 就 可 以 用 这 个 C h a n n e l 来 接 收 数 据 了。 反 过 来 , 我 们 可 以 用 a c t o r 启 动 一 个消 费 者 协 程 。

Channel的关闭

pr oduce和actor返回的Channel都会随着对应的协程执行完毕而关闭,也正是这样,Ch a n n e l 才 被 称 为热 数据 流 。
对于一个Channel,如果我们调用了它的close方法,它会立即停止接收新元素,也就是 说 这 时 它 的 i s C l o s e d F o r S e n d 会 立 即 返 回 t r u e 。 而 由 于C h a n n e l 缓 冲 区 的 存 在 , 这 时 候 可能还有 一些元素没有被处理完,因此要等所有的元素都被读取之后isClosedForReceive 才会 返 回 t r u e 。
Ch annel的生命周期最好由主导方来维护,建议由主导的一方实现关闭。

BroadcastChannel

前面提到,发送端和接收端在Channel 中存在一对多的情形,从数据处理本身来
讲,虽然有多个接收端,但是同一个元素只会被一个接收端读到。广播则不然,
多个接收端不存在互斥行为。
在这里插入图片描述

多路复用

什么是多路复用

数据通信系统或计算机网络系统中,传输媒体的带宽或容量往往会大于传输单一 信号的需求,为了有效地利用通信线路,希望一个信道同时传输多路信号,这就是 所 谓 的 多 路 复 用 技 术 (M u l t i p l e x i n g )。
在这里插入图片描述

复 用 多 个a w a i t

两个API分别从网络和本地缓存获取数据,期望哪个先返回就先用哪个做展示。
在这里插入图片描述

复用多个Channel

跟await类似,会接收到最快的那个channel消息。
在这里插入图片描述

SelectClause

我们怎么知道哪些事件可以被select呢?其实所有能够被select的事件都是SelectClauseN类型,包括:
• Select ClauseO:对应事件没有返回值,例如join没有返回值,那么onJoin就是SelectClauseN类型。使用时,onJ oin的参数是一个无参函数。
• SelectClause1:对应事件有返回值,前面的onAWait和onReceive都是此类情况。
• Select Clause2:对应事件有返回值,此外还需要一个额外的参数,例如Channel.onSend有两个参数,第一
个是Channel数据类型的值,表示即将发送的值;第二个是发送成功时的回调参数。

如果我们想要确认挂起函数是否支持select,只需要查看其是否存在对应的Select Clause
N类型可回调即可。

使用Flow实现多路复用

多数情况下,我们可以通过构造合适的Fl ow来实现多路复用的效果。
在这里插入图片描述

并发安全

不安全的并发访问

我们使用线程在解决并发问题的时候总是会遇到线程安全的问题,而Java 平台上
的Kotlin协程实现免不了存在并发调度的情况,因此线程安全同样值得留意。

协 程的并发工具

除了我们在线程中常用的解决并发问题的手段之外,协程框架也提供了一些并发 安全的工具,包括:
• Channel:并发安全的消息通道,我们已经非常熟悉。
• Mutex:轻量级锁,它的lock和unlock从语义上与线程锁比较类似,之所以轻量是因为它在获取
不到锁时不会阻塞线程,而是挂起等待锁的释放。
• Semaphore:轻量级信号量,信号量可以有多个,协程在获取到信号量后即可执行并发操作。
当 S e m a p h o r e 的 参 数 为 1 时 , 效 果 等 价 于M u t e x 。

避免访问外部可变状态

编写函数时要求它不得访问外部状态,只能基于参数做运算,通过返回值提供运 算结果。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1478483.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity | Shader基础知识(第十集:shader常用外部资产单词速成)

目录 一、外部资产简介 二、常用的外部资产单词 三、常用的外部资产单词和引入内部 四、图片资产外部调整的具体讲解 1.Tiling,中文:铺地砖 2.Offset,中文:偏移 五、作者的话 一、外部资产简介 在第六集中,我们…

新王炸:文生视频Sora模型发布,能否引爆AI芯片热潮

前言 前方高能预警,Sora来袭! 浅析Sora的技术亮点 语言模型中构建关键词联系 视频素材分解为时空碎片 扩散模型DiT Not for play, But change world! OpenAI的宏大目标 未来已来,只是尚未流行 Sora的成本与OpenAI的7万亿美金豪赌 算…

GPT-SoVITS音色克隆-模型训练步骤

GPT-SoVITS音色克隆-模型训练步骤 GPT-SoVITS模型源码一个简单的TTS后端项目 基于模型部署和训练教程,语雀 模型部署和训练教程 启动模型训练的主页面 1. 切到模型路径 /psycheEpic/GPT-SoVITS进入Python虚拟环境,并挂起执行python脚本 conda activ…

nginx使用详解--缓存使用

Nginx 是一个功能强大的 Web 服务器和反向代理服务器,它可以用于实现静态内容的缓存,缓存可以分为客户端缓存和服务端缓存。 客户端缓存 客户端缓存指的是浏览器缓存, 浏览器缓存是最快的缓存, 因为它直接从本地获取(但有可能需要发送一个协商缓存的请…

leetcode:1974. 使用特殊打字机键入单词的最少时间(python3解法)

难度:简单 有一个特殊打字机,它由一个 圆盘 和一个 指针 组成, 圆盘上标有小写英文字母 a 到 z。只有 当指针指向某个字母时,它才能被键入。指针 初始时 指向字符 a 。 每一秒钟,你可以执行以下操作之一: 将…

算法基础(三)(模拟)

1.模拟算法介绍: 模拟算法通过模拟实际情况来解决问题,一般容易理解但是实现起来比较复杂,有很多需要注意的细节,或者是一些所谓很“麻烦”的东西。模拟题一般不涉及太难的算法,一般就是由较多的简单但是不好处理的部…

RT-Thread+ENV+MDK+STM32CubeMX适配

前言 (1)如果有嵌入式企业需要招聘湖南区域日常实习生,任何区域的暑假Linux驱动/单片机/RTOS的实习岗位,可C站直接私聊,或者邮件:zhangyixu02gmail.com,此消息至2025年1月1日前均有效 &#xff…

T - SQL使用事务 及 在Winform使用事务

事务适用场景 1 事务使用在存储过程中,直接在数据库中进行编写 2 事务使用在Winfrom项目中 SQl:使用事务转账操作的实例 一般都会找一个变量记录错误的个数,error记录上一句sql的错误和错误编号 declare errornum int 0 -- 定义…

el-table 指定表格合并行与单元格,以及表头合并单元格

1&#xff1a;页面html <template><div class"container"><div class"flex-end"><el-button type"primary" click"allEndBtn">批量办结</el-button><el-button type"primary" click"…

【第十天】C++函数对象/仿函数、谓词、适配器及常见algorithm算法

一、函数对象 重载了函数调用运算符()的类 实例化的对象叫函数对象&#xff0c;也叫仿函数。 如果函数对象 有一个参数 叫&#xff1a;一元函数对象/仿函数如果函数对象 有二个参数 叫&#xff1a;二元函数对象/仿函数如果函数对象 有三个及以上参数 叫&#xff1a;多元函数对…

Java设计模式 | 七大原则之合成复用原则

基本介绍 合成复用原则&#xff08;Composite Reuse Principle&#xff09;尽量使用合成/聚合的方式&#xff0c;而不是使用继承 设计原则核心思想总结 找出应用中可能需要变化之处&#xff0c;把他们独立出来&#xff0c;不要和那些不需要变化的代码混在一起针对接口编程&…

Ubuntu系统下DPDK环境搭建

目录 一.虚拟机配置1.添加一个网卡(桥接模式)2.修改网卡类型3.修改网卡名称4.重启虚拟机5.查看网卡信息6.dpdk配置内存巨型页 三 DPDK源代码下载和编译1.下载源代码2.解压源代码3.安装编译环境4.编译5.设置dpdk的环境变量6.禁止多队列网卡7.加载igb_uio模块8.网卡绑定9.验证测试…

Docker 入门笔记

课程地址 容器技术概述 docker能做什么&#xff1a;将应用程序代码和依赖打包为一个镜像&#xff0c;作为交付介质&#xff0c;在各种环境中部署 相比于虚拟机&#xff0c;docker 只虚拟出一个隔离的程序运行环境&#xff0c;其需要则资源大大减少 容器内的程序就好像直接运…

安装 docker 可视化工具 portainer

portainer 官方网站 https://www.portainer.io/ 一、portainer 介绍 Portainer是一款开源的容器管理平台&#xff0c;它提供了一个直观易用的Web界面&#xff0c;帮助用户管理Docker容器集群、镜像、卷等资源。Portainer 支持多种 Docker 环境&#xff0c;包括本地Docker、Sw…

EXTJS实现自定义表格

宽度自适应 width: 100%, 高度自适应 height: 100% 同时设置表格所处页面高度100% html,body,#griddemo{height: 100%;} 自定义显示的文本内容 Ext.onReady(function () {Ext.QuickTips.init()function sexText(val) {if (val 0) {return <span style"color:green…

20240229作业

1.编写链表&#xff0c;链表里面随便搞点数据&#xff0c;使用 fprintf 将链表中所有的数据&#xff0c;保存到文件中&#xff0c;使用 fscanf 读取文件中的数据&#xff0c;写入链表中 #include <stdio.h> #include <stdlib.h>// 定义链表节点结构体 struct List…

Linux系统安装使用nginx

1.编译安装Nginx服务 (1)关闭防火墙&#xff0c;将安装nginx所需要软件包传到/opt目录下 systemctl stop firewalld systemctl disable firewalld setenforce 0 将压缩包传入到/opt目录下 cd /opt wget http://nginx.org/download/nginx-1.18.0.tar.gz (2). 安装依赖…

小红书的几种赚钱方式解读

小红书的七种变现方式&#xff1a; 1.通过小红书蒲公英平台接广告&#xff0c;粉丝数量大于1000的用户可以开通。单条笔记的广告费用从几百元到几十万不等。 2.开设小红书专栏&#xff0c;粉丝数量大于1万的用户可以开通。 3.进行私域变现&#xff0c;将小红书的咨询引导到微信…

解决内嵌帆软报表出现重定向问题

最近收到反馈&#xff0c;某些程序的前端通过iframe标签内嵌finebi帆软报表时&#xff0c;出现一系列问题。 问题1: 如下图所示&#xff0c;单点登录(单点登录地址schema是https)后service地址的schema协议是http, 浏览器内核的安全策略不允许http访问https。 解决方案&#xf…

HTTP笔记(五)

个人学习笔记&#xff08;整理不易&#xff0c;有帮助点个赞&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客 目录 一&#xff1a;HTTP报文首部 &#xff08;1&#xff09;HTTP请求报文 &#xff08;2&#xff09…