Kotlin 40. Dependency Injection 依赖注入以及Hilt在Kotlin中的使用,系列3:Hilt 注释介绍及使用案例
一起来学Kotlin:概念:27. Dependency Injection 依赖注入以及Hilt在Kotlin中的使用,系列3:Hilt 注释介绍及使用案例
此系列博客中,我们将主要介绍:
Dependency Injection
(依赖注入) 概念介绍。网上看了许多关于 DI 的介绍,云里雾里。这里,我们通过通俗易懂地方式对其进行介绍。- 手动依赖注入介绍。为了让大家更容易理解 Hilt,我们先介绍如何通过手动的方式实现依赖注入效果。
- Hilt 注释(annotations)介绍及使用案例
- MVVM 案例中如何使用 Hilt
此博客基于一个非常简单的 Kotlin 项目来解释 Hilt 的使用方式。
文章目录
- 一起来学Kotlin:概念:27. Dependency Injection 依赖注入以及Hilt在Kotlin中的使用,系列3:Hilt 注释介绍及使用案例
- 前言
- 1 回顾
- 2 Hilt 的相关注释(annotations)
- 2.1 `@HiltAndroidApp` 注释
- 2.2 `@AndroidEntryPoint` 注释
- 2.3 `@Inject` 注释
- 2.4 `@ViewModelInject` 注释
- 2.5 `@Module` 注释
- 2.6 `@Binds` 注释
- 2.7 `@InstallIn` 注释
- 2.8 `@Provides` 注释
- 3 Hilt 的简单案例
- 3.1 `AndroidManifest.xml`
- 3.2 `build.gradle (Project)`
- 3.3 `build.gradle (Module)`
- 3.4 Application Class `MyApp.kt`
- 3.5 `MainActivity.kt`
- 3.6 `DatabaseAdapter.kt`
- 3.7 `DatabaseService.kt`
前言
1 回顾
在系列的第一篇博客中,我们介绍了依赖注入的概念,以及为什么需要依赖注入。
在系列的第二篇博客中,我们介绍了手动依赖注入。我们并不建议在项目中使用手动依赖注入,但我们可以通过手动依赖注入的介绍,来解释Hilt主要完成的两件事:
- 提供了“containers”(容器)用来装各种依赖;
- 自动管理这些“containers”(容器)的“lifecycles”(生命周期)。
在下面的章节中,我们主要解决一个问题:Hilt 具体应该在项目中怎么使用。
2 Hilt 的相关注释(annotations)
我们先对 Hilt
涉及到的注释进行一一介绍,这些注释包括:
@HiltAndroidApp
@AndroidEntryPoint
@Inject
@ViewModelInject
@Module
@Binds
@InstallIn
@Provides
2.1 @HiltAndroidApp
注释
在我们的安卓工程项目中,如果要使用Hilt,必须要有一个自定义的Application才行。这里我们的 MyApp.kt
文件中需在该类上方标注 @HiltAndroidApp
:
@HiltAndroidApp
class MyApp : Application() {
...
}
2.2 @AndroidEntryPoint
注释
此注释可以将成员注入到各安卓组件中,例如活动(activities)、片段(fragments)、视图(views)、服务(services)和广播接收器(broadcast receivers)。
我们必须要使用 @AndroidEntryPoint
注释来注释安卓组件,才能接下来其中继续注入字段或方法(比如 @Inject 注释)。Hilt 目前支持以下安卓类:
- Activity(使用
@HiltAndroidApp
注释标注) - Fragment(使用
@AndroidEntryPoint
注释标注) - View(使用
@AndroidEntryPoint
注释标注) - Service(使用
@AndroidEntryPoint
注释标注) - Broadcast Receiver(使用
@AndroidEntryPoint
注释标注)
使用 @AndroidEntryPoint
注释一个安卓类需要注释所有依赖于它的类。每当我们注释一个 fragment 时,我们还必须注释使用该 fragment 的任何 activity。
比如,Activity:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}
}
对于 Fragment:
@AndroidEntryPoint
class CountriesListFragment : Fragment() {
...
}
2.3 @Inject
注释
当项目中的构造函数被 @Inject
注释时,它就可以作为依赖项在任何地方使用。比如上面 MainActivity.kt
中的 databaseAdapter
。也比如下面的例子:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private lateinit var binding: ActivityMainBinding@Injectlateinit var repository: DbRepository@Injectlateinit var taskAdapter: TaskAdapter@Injectlateinit var task: TaskEntityoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding= ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)... }
}
我们之前提到依赖注入的三种形式:
- constructor injection(类的构造函数注入):依赖项是通过类构造函数提供的。
- setter/field injection(类字段注入):客户端公开一个 setter 方法,注入器使用它来注入依赖项。
- interface injection:依赖项提供了一个注入器方法,可以将依赖项注入传递给它的任何客户端。 客户端必须实现一个接口,该接口公开一个接受依赖项的 setter 方法。
上面这个例子就是属于第二种。这里要明确说明一点,在使用 Hilt 做类字段注入的时候,变量名前面是不能加 private 关键字的。因为加了 private 之后,这个变量就变成了类私有的变量,Hilt 就没有权限访问了,也无从谈起依赖注入了。
这也就是我们在使用了 Hilt 之后,不需要像手动依赖注入时那样,在 Activity
类里面的 onCreate()
函数对这个变量进行赋值。而是使用 @inject
注释这个变量以后,直接在代码里使用。赋值的事情,是由 Hilt
帮我们代劳了。
2.4 @ViewModelInject
注释
和 @Inject
注释类似的,viewModel 里面的构造函数被 @ViewModelInject
注释时,它就可以作为依赖项在任何地方使用。@ViewModelInject
不是来自 Hilt
框架,而是来自 Hilt
支持的 Jetpack
库,它向 Jetpack
发出 ViewModel
已准备好注入的信号。这个注释是专门为 ViewModel
组件设计的。比如下面的例子:
@HiltViewModel
class CountriesListViewModel
@Inject constructor(private val repository: ApiRepository) : ViewModel() {
...
}
2.5 @Module
注释
对于接口来说,接口又没有构造函数,怎么 Inject 呢?这个时候,我们就需要 @Module
注释。
Hilt module
也是一个类,但是它需要在类名前面加上注释(annotation)@Module;同时,还需要加上 @InstallIn
,顾名思义,我们拆开来看这个注释:Install In,后面肯定跟的是一个作用域范围(scope),意思就是告诉Hilt,我们新建的这个 “Module” 类,作用范围是什么。这个范围(scope)的分类,我们后续将会提到,在这暂且先不用深究。
@Module
object ApiModule {
...
}
2.6 @Binds
注释
前面我们说过,接口是没有构造函数的,所以也无法使用 constructor injection
的方式进行依赖注入,那么我们怎么样才能让 Hilt
知道我们需要这个接口的实例作为依赖呢?这时候需要使用注释(annotation)@Binds
来告诉 Hilt
。不过有一项准备工作我们还要先做,那就是先得有一个接口的实现类。这样 Hilt
才会知道使用哪个实现类去实现这个接口,相关示例代码如下:
interface AnalyticsService {<!-- -->fun analyticsMethods()
}/*接口AnalyticsService 的实现类需要 Constructor-injected,
Hilt 需要使用到*/
class AnalyticsServiceImpl @Inject constructor(...
) : AnalyticsService {<!-- --> ... }@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {<!-- -->@Bindsabstract fun bindAnalyticsService(analyticsServiceImpl: AnalyticsServiceImpl): AnalyticsService
}
AnalyticsService
是一个接口,AnalyticsServiceImpl
是 AnalyticsService
接口的实现类,同理 AnalyticsServiceImpl
的构造函数前也需要加上注释 @Inject
告诉 Hilt
在哪可以找到它。
最后就到我们的 Hilt Module 了,它前面有两个注释:@Module
和 @InstallIn
(ActivityComponent::class)。这两个注释总结起来就是告诉 Hilt
,这个 Module
的可见范围是所有的Activity类。因为返回的是 AnalyticsService
接口类型,所以我们这里使用抽象类和抽象函数bindAnalyticsService
来实现这个 Hilt Module。
抽象函数 bindAnalyticsService
前面是 @Binds
注释,它的参数就是接口 AnalyticsService
的实现类 AnalyticsServiceImpl
,函数返回类型就是接口 AnalyticsService
。这样,Hilt就可以准确地把它的实例注入到依赖于它的地方了。
总结一下,就是对于接口实例的依赖注入,需要使用三个注释:@Module
,@InstallIn
和 @Binds
。
2.7 @InstallIn
注释
在 @Module
注释的使用过程中,我们已经提到了 @InstallIn
注释的使用。通过添加 @InstallIn
注释,我们将此模块类提供的依赖对象的使用限制为特定的安卓组件。以下是另一个例子:
@Module
@InstallIn(SingletonComponent::class)
object ApiModule {
...
}
Hilt
提供了七个与 @InstallIn
注释兼容的组件。@Module
注释告诉 hilt 框架,它提供的依赖对象只能在 @InstallIn
注释中命名的特定组件的生命周期内被注入和使用。
- @InstallIn(ApplicationComponent) — present for the lifetime of the application.
- @InstallIn(ActivityComponent) — present for the lifetime of the Activity.
- @InstallIn(ActivityRetainedComponent) — present for the lifetime of a configuration surviving activity (i.e) surviving orientation changes just like the ViewModel.
- @InstallIn(FragmentComponent) — present for the lifetime of the fragment.
- @InstallIn(ServiceComponent) — present for the lifetime of the service.
- @InstallIn(ViewComponent) — present for the lifetime of the view that is directly inside an activity.
- @InstallIn(ViewWithFragmentComponent) — present for the lifetime of the view inside a fragment.
2.8 @Provides
注释
当我们需要对第三方库进行依赖注入的时候,就不能使用注释(annotation)@Binds
了,为了以示区分,Hilt
提供了一个新的注释 @Provides
。
其实 Hilt
的注释取名还是很考究的,接口是需要“绑定”(@Binds
)的,而第三方库是需要“提供”(@Provides
)的。
假如一个 AnalyticsService
类实现了一个第三方库 Retrofit
,这时候,我们只需要在 Hilt
的 Module
中实现一个函数,函数名可以任意起,目的是要告诉 Hilt
,怎么来构建这个 AnalyticsService
类的实例对象,示例代码如下:
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {<!-- -->@Providesfun provideAnalyticsService(): AnalyticsService {<!-- -->return Retrofit.Builder().baseUrl("https://example.com").build().create(AnalyticsService::class.java)}
}
与前面的注解 @Binds
例子相比,在这个例子中主要是把 @Binds
改成了 @Provides
,函数 provideAnalyticsService
返回的是一个使用 Retrofit
构建的 AnalyticsService
类的实例。
这样,Hilt
就可以在需要 AnalyticsService
类实例(依赖)的地方,把它的实例注入进去。
3 Hilt 的简单案例
在这里,我们介绍一个非常简单的 Hilt 案例,大家可以跟着我们一起在 Android Studio 上新建一个安卓的应用,然后按照下面的步骤一步步添加相关依赖和代码。
3.1 AndroidManifest.xml
Hilt 框架会在我们首次构建项目时为项目创建一个基类 Hilt_MyApp。 我们不需要直接扩展基类,因为它会自动创建带注释的类 MyApp。这里我们需要在 AndroidManifest.xml
文件中添加 android:name=".MyApp"
,如下所示:
<applicationandroid:name=".MyApp"... ><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>
</application>
3.2 build.gradle (Project)
我们需要在 build.gradle (Project)
中添加 Hilt
对应的 classpath。代码如下:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {dependencies {classpath 'com.google.dagger:hilt-android-gradle-plugin:2.43.2'}
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {id 'com.android.application' version '7.2.0' apply falseid 'com.android.library' version '7.2.0' apply falseid 'org.jetbrains.kotlin.android' version '1.6.10' apply false
}task clean(type: Delete) {delete rootProject.buildDir
}
3.3 build.gradle (Module)
我们需要在 build.gradle (Module)
中添加 Hilt
对应的依赖
implementation 'com.google.dagger:hilt-android:2.43.2'
kapt 'com.google.dagger:hilt-compiler:2.43.2'
并且 plugins 中也需要添加:
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
代码如下:
plugins {id 'com.android.application'id 'org.jetbrains.kotlin.android'id 'kotlin-kapt'id 'dagger.hilt.android.plugin'
}android {compileSdk 32defaultConfig {applicationId "com.example.hiltex1"minSdk 27targetSdk 32versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}kotlinOptions {jvmTarget = '1.8'}
}dependencies {implementation 'androidx.core:core-ktx:1.7.0'implementation 'androidx.appcompat:appcompat:1.3.0'implementation 'com.google.android.material:material:1.4.0'implementation 'androidx.constraintlayout:constraintlayout:2.0.4'testImplementation 'junit:junit:4.13.2'androidTestImplementation 'androidx.test.ext:junit:1.1.3'androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'//Hiltimplementation 'com.google.dagger:hilt-android:2.43.2'kapt 'com.google.dagger:hilt-compiler:2.43.2'
}
3.4 Application Class MyApp.kt
在我们的安卓工程项目中,如果要使用Hilt,必须要有一个自定义的Application才行。这里我们的 MyApp.kt
文件中需在该类上方标注 @HiltAndroidApp
:
@HiltAndroidApp
class MyApp : Application() {
...
}
3.5 MainActivity.kt
在这里,我们写一个很简单的 MainActivity.kt
文件,代码如下:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var databaseAdapter: DatabaseAdapteroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)Log.d(TAG,"DatabaseAdapter : $databaseAdapter")databaseAdapter.log("Hey Hilt")}
}
这里我们使用到了 @AndroidEntryPoint
注释。AndroidEntryPoint 也就是上是其所相关联的依赖项的入口点(EntryPoint)。 我们需要告诉 Hilt
我们希望在何处注入依赖项。这就是AndroidEntryPoint的作用。它定义了将在何处提供依赖项。
Hilt 在这里的主要目的是尝试标准化注入功能,并消除尽可能多的组件耦合。AndroidEntryPoint 会自动为系统构建这些依赖项和组件。 所以我们不必再像前一章节那样去进行手动的依赖注入。当然,需要再强调一次,如果我们使用 AndroidEntryPoint 注释 fragment 并且它包含依赖项,则还必须注释使用到该 fragment 的 Activities。即,任何依赖于我们正在注释的这个类的相关类,依赖项,组件等,同样需要被注释。
在我们往下看其他代码之前,关注一下这行代码:
@Inject
lateinit var databaseAdapter: DatabaseAdapter
看似平平无奇,但实际上,这就是前面提到依赖注入的三种形式之一:setter/field injection(类字段注入)。在这个例子中,我们希望将 databaseAdapter 注入到 main activity 中。
3.6 DatabaseAdapter.kt
这里有提到依赖注入的三种形式之一:constructor injection(类的构造函数注入)。在 DatabaseAdapter.kt
中,我们就要使用到:
class DatabaseAdapter @Inject constructor(var databaseService: DatabaseService) {fun log(msg: String){Log.d(TAG,"DatabaseAdapter : $msg")databaseService.log(msg)}
}
创建依赖(dependency)的最基本、最简单的方法是通过构造函数注入。 一个组件(component)本质上是一个不带参数的类,我们只需要添加 inject 注解,这样就可以随时将其注入到需要的地方(又比如 class SampleClass @Inject constructor()
)。
3.7 DatabaseService.kt
这也是一个类的构造函数注入的例子。
class DatabaseService @Inject constructor() {fun log(msg: String){Log.d(TAG,"DatabaseService msg : $msg")}
}
大家有没有发现,在用了 Hilt
之后,依赖注入的使用变得非常简单,代码也变得非常简洁(我们可以对比一下系列2中的手动依赖注入案例)。
相关文章:
Kotlin 40. Dependency Injection 依赖注入以及Hilt在Kotlin中的使用,系列3:Hilt 注释介绍及使用案例
一起来学Kotlin:概念:27. Dependency Injection 依赖注入以及Hilt在Kotlin中的使用,系列3:Hilt 注释介绍及使用案例 此系列博客中,我们将主要介绍: Dependency Injection(依赖注入)…...
1000亿数据、30W级qps如何架构?来一个天花板案例
1000亿级存储、30W级qps系统如何架构?来一个天花板案例 说在前面 在尼恩的(50)读者社群中,经常遇到一个 非常、非常高频的一个架构面试题,类似如下: 千万级数据,如何做系统架构?亿…...
人工智能及其应用(蔡自兴)期末复习
人工智能及其应用(蔡自兴)期末复习 相关资料: 人工智能期末复习 人工智能复习题 人工智能模拟卷 人工智能期末练习题 1 ⭐️绪论 人工智能:人工智能就是用人工的方法在机器(计算机)上实现的智能࿰…...
openpnp - configure - 矫正里程碑
文章目录openpnp - configure - 矫正里程碑概述备注ENDopenpnp - configure - 矫正里程碑 概述 进入矫正里程碑了 查找问题 现在第一个问题是X轴的齿隙矫正 根据提示, 将顶部相机移动到主基准点上, 选择容差(就选用默认的0.025), 开始矫正. 正好开机后, 使能了视觉原点归零. …...
JavaScript高级程序设计读书分享之8章——8.2创建对象
JavaScript高级程序设计(第4版)读书分享笔记记录 适用于刚入门前端的同志 创建Object的实例 let person new Object(); person.name "Nicholas"; person.age 29; person.job "Software Engineer"; person.sayName function() { console.log(this…...
关于Could not build wheels for opencv-python-headless, which is...报错的解决方案
在通过最新版pip在线安装package:opencv-python-headless的时候,会产生报错信息,主要为 ERROR: Failed building wheel for opencv-python-headless ERROR: Could not build wheels for opencv-python-headless, which is required to insta…...
【K3s】第1篇 K3s入门级介绍及架构详解
1、什么是 K3s? K3s 是一个轻量级的 Kubernetes 发行版,它针对边缘计算、物联网等场景进行了高度优化。K3s 有以下增强功能: 打包为单个二进制文件。使用基于 sqlite3 的轻量级存储后端作为默认存储机制。同时支持使用 etcd3、MySQL 和 PostgreSQL 作…...
Java学习--反射
1. 反射 1.1 反射的概述: **专业的解释(了解一下):**是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意属性和方法ÿ…...
应用和迭代(名词解释)
应用和迭代是什么意思 应用: ● 一个完整的前端应用,一般用应用脚手架创建,包含路由,页面,状态等 ● 一个应用对应一个代码仓库 ● 应用的分组(业务中心,数据中台等)只用于逻辑分类&…...
HTMLCollection 和 NodeList 区别
Node 和 Element DOM 是一棵树,所有节点都是 NodeNode 是 Element 的基类Element 是其他 HTML 元素的基类,如 HTMLDivElement HTMLCollection 和 NodeList HTMLCollection 是 Element 的集合NodeList 是 Node 的集合 <body><p id"p1&qu…...
fork()出来一个进程,这个进程的父进程是从哪来的?
基本概念fork() creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process.fork()是一个系统调用,不是一个函数。详细信息可以,man…...
结构体内存对齐
结构体相信大家已经了解过了,现在我们深入讨论一个问题,计算结构体的大小 也是很热门的一个考点:结构体内存对齐 先看看下面结构体的大小 typedef struct Test {char a;char b;char c; }Test; 很容易看出答案为3,结构体的大小位…...
【C语言进阶】指针进阶
今日所做之事勿候明天,自我所做之事勿候他人。 --歌德 目录 指针进阶(更深层次的理解): 一.字符指针 二.指针数组 三.数组指针 1.数组指针的定义: 2.&数组名和数组名: 3.数组指针的使用: 四.数组参数,指针参数 1.一维数组传参:…...
java:Class的isPrimitive方法使用
java:Class的isPrimitive方法使用 1 前言 java中Class类的isPrimitive方法,用于检查类型是否为基本类型。java虚拟机创建了int、byte、short、long、float、double、boolean、char这8种基础信息,以及void,一共9种。为这9种类型时…...
TCP 握手过程 三次 四次
蛋老师视频 SYN 同步 ACK 确认 FIN 结束 核心机制是确定哪些请求或响应需要丢弃 SYN、ACK、FIN 通过 1/0 设置开启/关闭 开启SYN后,报文中会随机生成 Sequence序号 用于校验 (应用可能发起多个会话,可以区分) 服务器的同步序…...
windows 下 安裝mysql 5.7.41 (64位) 超简单方式
文章目录1. 安装包下载2.安装步骤3. 服务卸载方式4. 配上 my.ini 常用配置1. 安装包下载 注意,截至2023年2月23日,MySQL所有版本不提供ARM芯片架构的Windows版本(8.0.12开始支持Red Hat系统的ARM版本),所以ARM架构的Windows无法安装MySQL&am…...
二叉树——二叉树的最近公共祖先
二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一…...
数据结构与算法基础-学习-14-线性表之串
一、串的定义由0-n个字符组成的有限序列。(n>0)二、串的相关术语1、子串串中任意个连续字符组成的子序列成为该串的子串。2、主串包含子串的串成为主串。3、字符位置字符在序列中的序号为该字符在串中的位置。4、子串位置子串第一个字符在主串中的位置…...
Mac 快捷键
目录 命令行快捷键 命令行快捷键 control d 命令行中代表发送EOF终止输入 control u 删除光标之前到行首的字符 control k 删除光标之前到行尾的字符(比较常用) control a 移动光标到行首(常用) control e 移动光标到行尾 control l 清屏,相当于clear命令 con…...
【微服务】-微服务环境搭建
目录 2.1 技术选型 2.2 模块设计 2.3 微服务调用 2.4 创建⽗⼯程 2.5 创建商品微服务 2.6 创建订单微服务 2.1 技术选型 持久层: SpingData Jpa 数据库: MySQL5.7 其他: SpringCloud Alibaba 技术栈 2.2 模块设计 --- shop-parent ⽗⼯程 --- shop-product-api 商品微服…...
IGKBoard(imx6ull)-ADC编程MQ-2烟雾传感器采样
文章目录1- ADC介绍2- MQ-2烟雾传感器介绍(1)工作原理(2)MQ-2应用电路3- MQ-2烟雾传感器硬件连接4- ADC驱动配置5- 编程查看当前浓度1- ADC介绍 ADC是Analog-to-Digital Converter的缩写,指模数转换器。真实世界的模拟…...
前端二面vue面试题总结
什么是 mixin ? Mixin 使我们能够为 Vue 组件编写可插拔和可重用的功能。如果希望在多个组件之间重用一组组件选项,例如生命周期 hook、 方法等,则可以将其编写为 mixin,并在组件中简单的引用它。然后将 mixin 的内容合并到组件中…...
时间API在更新,传奇已经谢幕,但技术永远不死
(Bill Joy(左一),Vinod Khosla(左二),Andy Bechtolsheim(右二),Scott McNealy(右一) ) CSDN 博文征集活动(和日期相关的代码和bug):点击这里 各位 “big guys”,这篇博文…...
SQL调优指南笔记22:Gathering Diagnostic Data with SQL Test Case Builder
本文为SQL Tuning Guide 第21章“Gathering Diagnostic Data with SQL Test Case Builder”的笔记。 SQL Test Case Builder 是一种工具,可自动收集在不同数据库实例中重现问题所需的信息。 SQL 测试用例是一组信息,使开发人员能够为遇到性能问题的特定…...
从0开始学python -43
Python3 正则表达式 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。 Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。 re 模块使 Python 语言拥有全部的正则表达式功能。 compile 函数根…...
Kafka基本原理
总述 简介 Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各…...
css3的重点内容
css3的重点内容 浮动 父级边框塌陷问题 浮动的清除 clear:left; //清除左侧浮动 clear:right; //清除右侧浮动 clear:both; //清除两侧浮动解决方案 增加父级元素的高度增加一个空的div,之后清除浮动通过overflow来进行相关元素的修剪给父类添加相应的伪类元素…...
《Roller: Fast and Efficient Tensor Compilation for Deep Learning》
《Roller: Fast and Efficient Tensor Compilation for Deep Learning》 用于深度学习 快速高效的张量编译器 作者 微软亚洲研究院以及多伦多大学等多所高校 摘要 当前编译为了产生高效的kernel时,搜索空间大,通常使用机器学习的方法 找到最优的方案…...
顺丰同城测试开发一面 49min答案,全文7000字,面试总结都在这里了
今天给大家分享一份顺丰同城的测试开发一面面试真题。老规矩,当你看到这份面试题的时候,先不要着急去看答案,你可以想想假如你在面试现场,你会怎么回答?这个思考的过程其实也是很重要的。 全文7000字干货,…...
docker启动容器服务之后访问失败
关于docker启动容器服务之后,宿主机访问失败(解决方法) 注:在进行docker容器启动宿主机进行容器访问时,无需进行网络的配置,docker容器在启动时会自动解决 第一种原因及修改方法 在进行启动的时候&#…...
wordpress建立网站吗/小红书笔记关键词排名优化
通常情况 通常程序的UI不太复杂,我们会直接加载这些UI信息复杂的UI加载的元素就相对多一些。加载的数据相对多。因为UI元素和数据元素都比较多,加载的时间相对多。 可视者优先加载不是默认的加载顺序,而是有选择的加载一些首先用户看到的UI&a…...
企业网站无线端怎么做/南京seo公司排名
一、整体大纲 二、 系统IO函数 1. 一些概念 文件描述符 PCB C库函的IO缓冲区 1) 文件描述符 int 类型 一个进程最多可打开多少文件 2) pcb 进程控制块 在其中有一个文件描述符表 -- 数组[1024…...
什么网站可以查房屋建筑面积/百度seo快速排名
奋斗的小孩系列 FPGA学习altera系列: 第十一篇 流水灯设计 作者:奋斗的小孩 郝旭帅(转载请注明出处) 大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢…...
公司做外地网站/开鲁seo网站
vector<:vector>> allcontourpoint;//二层容器 std::vector<:point> Pointpoly; //一层容器 allcontourpoint.pop_back(); //弹出上一个, allcontourpoint.push_back(Pointpoly); //存储一个 vector>contours;//轮廓 allco…...
深圳做微信网站设计/河南平价的seo整站优化定制
大家好,最近不少小伙伴在学 Python,想找个好玩的练手项目。那今天分享一个简单、好玩,适合新手的 Python 小项目。文章较长,建议收藏、喜欢关注、点赞,文末提供技术交流群。 以下是具体项目: 本文将以哔哩…...
国外网页设计分享网站/最新军事消息
0. 前言Chrome59(linux、macos)、 Chrome60(windows)之后,Chrome自带headless(无界面)模式很方便做自动化测试或者爬虫。但是如何和headless模式的Chrome交互则是一个问题。通过启动Chrome时的命令行参数仅能实现简易的启动时初始化操作。Selenium、Webdriver等是一…...