Hilt 实战 | 创建应用级别 CoroutineScope

在遵循 协程最佳实践 时,您可能需求在某些类中注入运用等级效果域的 CoroutineScope,以便能够创立与运用生命周期相同的新协程,或创立在调用者效果域之外仍能够作业的线程池作业原理新协程。

经过本文,您将学习怎样经过 Hilt 创立运用等级效果域的 CoroutineScope,以及怎样将其作为依托项进行注入。咱们将在示例中展现怎样注入不同的 CoroutineDispatcher 以及在查验中替换其完毕,进一步优化协程的运用。

手动依托项注入

在不运用任何库的状况下,遵循依托项注入 (DI) 的线程池怎么确保线程履行次序最佳实践方案来 手动 创APP建一个运用等级效果域 的 CorouappstoretineScope,一般会在 Application 类中approach添加一个 Corouti协程appneScope 实例变量。当创立其他政策时,手动将相同的 CoroutineScope 实例android平板电脑价格分发到这些政策中。

clandroid/yunosass Myandroid的drawable类Repository(private val externalScope: CoroutineScope) { /* ... */ }
class MyApplication : Application()协程游览 {
// 运用中任何类都能够经过 applicationContext 拜访运用等级效果域的类型
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
val myRepository = MyRepository(applicationScopeandroid电子市场)
}

由于在线程池作业原理 Android 中没有牢靠的方法来获取 Application 销毁的机遇,而且运用等级的效果域以及任何正在线程池的效果实施的任务都将同运用进程的完毕一起销接口自动化毁,也意味着您无需手动调用 applicationScope.cancel()

手动注入更高雅的做法是创立一个 ApplicationCo线程池面试题ntainer 容器类来持有运用等级协程游览效果域的类型。这有助于关注点别离,由于容器类具有如下责任:

  • 处理怎样结构切线程池当类型的逻辑;
  • 持有容器等级效果域的appointment类型实例;
  • 回来束缚效果域或未束缚效果域的类型实例。
class App线程池的七个参数licationDiContainer {
val applicationScope = Coroutin协程appeScope(SupervisorJob() + Dispatchers.Default)
val myRepository = MyRepository(applicationScope)
}
class M线程池的七个参数y接口crc错误计数Application : Apappreciateplication线程池作业原理() {
val applicationDiContainer = ApplicationDiContainer()
}

阐明: 容器类永approach久回来被束缚效果域的类型的相同实例,而且永久回来未被束缚效果域的类接口crc错误计数型的不同实例。将类型的效果域束缚到容器类中 成线程池的七个参数本很高,这是由于在组件销毁之前,被束缚效果域的政策将一贯存在于内存中,所以仅在真实需求束缚效果域的场景运接口卡用。

在上述 ApplicationDiContainer 示例中,所有的类型都被束缚了效果域。假定 MyRepository 无需将效果域束缚为 Applicati线程池原理on,咱们能够这样做:

candroid下载安装lass Applicat线程池原理ionDiContainer {
// 束缚效果域类型。永久回来相同的实例
val applic线程池有几种ationScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
// 未束缚效果域类型。永久回来不同实例
fun getM接口crc错误计数yRepository(): MyRepository {
return MyRepository(applicationScope)
}
}

在运用中运用 Hilt

在 Hilt 中,能够经过运用注解在编译期生成 ApplicationDiContainer 的内容 (甚至更多)!而且 Hilt 除 Application 类外,还为大部分 Android Framework 类供协程机票应了容器。android体系

在您的运用中配备 Hilt 而且创立 Application 类的容器,能够在 Application 类中运用 @HiltAndroidApp 注解。

@HiltAndroidApp
classMyApplication:Application()

此刻,运用 DI 容器现android电子市场已能够协程 线程运用了。咱们只需求让 Hilt 知道怎样供给不同类型的实例。

阐明 : 在 Hilt 中,容器类被引用为组件。appstore Application 相关的组件被称为 SingletonComponent**。请参阅 —— Hilt 供给的组件列表**:

结构方法注入

关于咱们能够拜访结构方法的类,结构方法注入是一个简略的方案来让 Hilt 知道怎样供给类型的实例,由于咱们只需求在结构器上添加 @Inject 注解:

@S接口无权限是什么意思ingleton // 束缚效果域为 Singl协程etonComponent
class MyRepository @Inject constructor(
private val externalScope: CoroutineS线程池的创立方法有几种cope
) {
/* ..apple. */
}

这让 Hilt 知道,为了供给一个 MyRepository 类的实例,需求传递一个 CoroutineScope 的实例作为依托线程池创立的四种项。Hil协程t 在编译期生成代码,以确保结构类型协程之窗的实例时能够正确创立并传入所需依托项,或许在条件缺少时报错。运用 @Singleton 注解,将该类的效果域束缚为 SingletonContainer

此刻,Hilt 还不知道怎样供给满足要求的 CoroutineScope 依托项,由于咱们还没有告知 Hilt 该怎样处理。 接下来apple的部分将展现怎样让 Hilt 知道应该传递哪些依托项。

阐明 : Hiappstorelt 供给了多种注解,来完毕将类型的效果域束缚到各种 Hilt 的现有组件中。请参阅 —— H协程官网ilt 供给的组件列表。

绑定

线程池的七个参数接口卡 是 Hilt 中的一个常见术语,它标清楚 Hilt 所知的怎样供给类型的实例作为依托项的信息。咱们能够说,上协程教育文的代码片段便是运用 @Inject 在 Hilt 中添加了绑定。

绑定遵循 组件层次结构。在 SingletonComponent 中可用的绑定接口无权限,在 ActivityComponent 中相同可用。

未束缚效果域的类协程教育型的绑定 (假定android下载安装上文的 MyRepositoryandroid/yunos码去掉 @Singleto协程教育n 便是一个例线程池有几种子),在任何 Hilt 组件中都可用。将绑定的协程机票效果域束缚到一个组件,例如被 @Singleton 注解的 MyRepository,能够在其时效果域的组件以及该层级以下的组件中运用。

经过模块供给类型

经过上述内容,咱们需求让 Hilt 知线程池道怎样供给合适的 C协程 线程oappearanceroutineScope 的依托项。但是 Corandroid/yunosoutineScope 是一个外部依托库供给的接口测验接口类型,所以咱们不能像之前处理接口 MyRepository 类相同运用结构方法注入。取而代之的方案是经过 运用模块,让 Hilt 知道实施协程游览哪些代码来供给类型实例。

@InstallIn(SingletonComponent::class)线程池的效果
@Module
object CoroutinesScopesMod接口无权限是什么意思ule {
@Singleton  // 永久供给相同实例
@Provides
fun providesCoroutineScope(): Co线程池原理routineScope {
// 当供给 CoroutineScope 实例时,实施如下代码
return CoroutineS协程机票cope(SupervisorJob() +app下载 Dispatchers.Default)
}
}

@Provides 注解的方法一起被 @Singleton 注解,让 Hilt 总是回来相同的 Corou接口自动化tineScope 实例。这是由于任何需求遵循运用生命周期的任务都应该运用遵循运用生命周期的 CoroutineScope 的同一实例创立android什么意思

@InstallIn 注解线程池的 Hilt 模块,标明接口无权限该绑定被装载到哪个 Hilt 组件中 (包含该组件层级以下的组件)。在咱们的案例中,被束缚效果域到 SingletonComponent 上的 MyRepository,需求运用等级的 CoroutineScope,该绑定相同需求被装载接口和抽象类的差异SingletonComp协程onent 中。android平板电脑价格

假定运用 Hilt 的行话,能够说成咱们添加了一个 CoroutinappleeScope 绑定,至此,Hilt 就知道怎样供给 CoroutineScope 实例了。

但是,上述代码片段Android仍能够优化。协程中硬编码 Dispatcher 不是出色的完接口自动化结,咱们需求注入它们使得这些 Dispatcher 可配备而且易于查验。根据之前的代码,咱们能够创立一个新的 Hilt 模块,协程app让它知道为每种状况需求注入哪个 Dispatcher: main、default 仍是 IO。

供给 CoroutineDispatcher 的完毕

咱们需求供给相同类型 CoroutineDispatcher 的不同完毕。换句话说便是,咱们需求相同类型的不同绑定。

咱们能够运用 束缚符 来让 Hilt 知接口crc错误计数道每种状况需求运用哪种绑定或许完毕。束缚符仅仅您和 Hilt 之间用来标识特定绑定的注解。让咱们为每一种 CoroutineDispatcher 的完毕创立一个约协程游览束符:

// CoroutinesQualifiappearanceers.kt 文件
@Retention(AnnotationRetent线程池作业原理ion.RUNTIME)
@Qualifier
annotation class DefaultDispatcher
@Retention(AnnotationReteandroid的drawable类ntion.RUNTIME)
@Qualifier
annotation class IoDispatcher
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
anapplenotation class MainDiappearancespatcher
@Retention(AnnotationRetention.BINARY线程池作业原理)
@Qualifier
annotation class MainImmediateDispatcher

接下来,在 Hilt 模块中运用这些束缚符注解不同的 @Provides 方法来表明特定的绑定。@DefaultDispatcher 束缚符注解的方法回来默许的 Dispatcher,其他束缚符不再赘述。

@InstallIn(SingletonComponent::class)
@Module
object CoroutinesDispatchersModule {
@DefaultDispatcher
@Provides
fun providesDefaultDispatcher(): Corout协程之窗ineDispatcher = Dispatchers.Default
@IoDispatcher
@Provides
fun provid接口是什么esIoDispatcher(): CoroutineDispatc线程池原理her = D接口卡ispandroid下载安装atchers.IO
@MainDispatcher
@Provides
fun providesMainDisp接口调用失利是什么意思atcher(): CoroutineDispatcher = Di接口调用失利是什么意思spatchers.Main
@MainImme线程池怎么确保线程履行次序diateDispatcher
@Provides
funapple providesMainImmediateDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
}

需求留心,这些 CoroutineDispatcapplehers 无需束缚效果域到 SingletonComponent。每次需求这些依托项时,Hilt 调用被 @Provides 注解的方法回来对应线程池面试题CoroutineDispatcher

供给运用等级效果域的 Coroutine接口是什么Scope

appointment了从咱们之前的运用等级效果域的 CoroutineScope 代码中摆脱硬编码 Cor线程池的创立方法有几种ouapplicationtineDispatcher,咱们需求注入 Hilt 供给的默许 Dispatcher。为此,咱们能够线程池创立的四种传入咱们想要注入的类型: CoroutineDispatcher,在供给运用等级 CoroutineScope 的方法中运用对应的束缚符线程池怎么确保线程履行次序 @Dandroid的drawable类efaultDi线程池怎么确保线程履行次序spatcher 作为依托项。

@In接口是什么stal接口卡lInandroid/yunos(SingletonComponent::clasandroid下载安装s)
@Modul线程池作业原理e
object CoroutinesScopesModule {
@Singleton
@Provides
fun providesCoroutineSc协程机票ope(
@DefaultDispatcher defa接口卡ultDispatcher: CoroutineDispatcher
): CoroutineScope = CoroutineScope(SupervisorJob() + defaultDispatcher)
}android电子市场

由于 Hilt 对 Co接口crc错误计数routineDispatcher 类型具有多个绑定,因此当 C接口调用失利是什么意思oroutineDispatcher 用作依托项时,咱们运用 @Defau接口调用失利是什么意思ltDispatcher 注解消除它的歧义。

运用等级效果域束缚符

虽然咱们现在不需求 Coroutandroid什么意思ineScope 的多个绑定 (未来咱们可apple能需求像 UserC线程池怎么确保线程履行次序oroutineScope这样的协程效果域),但是向运用等级 C线程池创立的四种oroutineScope 添加束缚符能够行进其作为依托项注入时的可读性。

@Retention(AnnotationRetention.RUNTIM协程appE)
@Qualifier
annotation class ApplicationScope
@InstallIn(SingletonComponent::class)
@Module
object Coroutine线程池原理sScopesModappearanceule {
@Singleton
@ApplicationScope
@Provides
fun p接口和抽象类的差异rovidesCoroutineScope(
@DefaultDispatcher defa线程池ultDispatcher: CoroutineDispatcher
): Corouti协程客服电话neScope = Coandroid手机routineScope(SupervisorJob() + defaultDispatcher)
}

由于 My接口和抽象类的差异Repository 依托该 CoroutineScope,因此能够非协程机票常清楚地知道接口无权限 externapproachalScope 运用哪种完毕:

@Singleton
class MyRepository @Inject constructor(
@ApplicationScope private val externalScope: CoroutappstoreineScope
) { /* ... */ }

在插桩接口调用失利是什么意思查验中替换 Dispatcher

如上所述,咱们应该注入 Dispatcher 使查验线程池创立的四种更简略并能够完全操控发生的事情。关于插桩查验,咱们希望 Espresso 等候协程完毕。

咱们能够利用 AsyncTask API 来替代运用 Espresso 闲暇资源 创立自定义 CoroutineDispatcher,来等候协程的完毕。即使 AappointmentsyncTas接口和抽象类的差异k 现已在 Android API 30 中被弃用,但 Espresso 会 hook 到其线程池中来检查闲暇状况。因线程池怎么确保线程履行次序此,任何应该在后台实施的协程都能够在 AsyncTask协程协程之窗线程池中实施。

在查验中能够运用 Hilt Tandroid平板电脑价格estInstallIn API 让 Hilt 供给一个类型的不同完毕。这与上文供给不同 Dispatcher 相似,咱们能够在 androidTest 包下创立一个新文件,来供给不同的 Dispatcher 完毕。

// androidTest/projectPath/TestCoroutinesDispatche线程池面试题rsMouule.kt 文件
@TestInstallIn(
comandroid/yunosponents = [SingletonComponent::class],
replaces = [Cor协程outinesDispatchersModule协程网::class]
)
@Module
object TestCoroutinesDispatchersModule {
@DefaultDispat协程 线程cher
@Provides
fun providesDefaultDispatcher(): Corout线程池面试题ineDispatche接口无权限是什么意思r =
Async协程appTask.THapplicationREAD_POOL_EXECUTOR.asCoroutiappleneDispatcher()
@IoD协程游览ispatcher
@Provides
fun providesIoDispatcher(): CoroutineDispatcher =
AsyncTask.THREAD_POOL_EXECUTOR.asCoroutineDispatcher()
@MainDispatcher
@Provides
fun providesMaappleinDispatcher(): Corouandroid手机tin线程池eDispatcher =线程池的创立方法有几种 Di接口测验spatchers.Main
}

经过上述代码,咱们让 Hilt 在查验中 “遗忘” 了在生产代码中运用的 Coroutiandroid体系nesDispatchersModule。该模块将会被替换为 TestCoroutinesDispatchersModuleandroid下载安装,它运用 AsyncTask 的线程池来处理后台作业,而 Dispa接口和抽象类的差异tchers.Main 则效果于主线程,这也是 Espresso 等候的政策线程。

警告 : 这其实是经过 hack 的方法完毕的,虽然不值得夸耀,但是由于 Espresso 现在没有方法知道 CoroutineDispatcher 是否处于闲暇状接口无权限是什么意思态 (issue 链接),所以协程并不能与其完美的集成。由于 Espresso 不是运用闲暇资源来检查该 execu接口调用失利是什么意思tor 是否闲暇,而是经过消息队伍中是否有内容的方法,所接口crc错误计数 AsyncTask.THREAD_POOL_EXECUTOR 是现在最佳的替代方案。也正是这些原因,使得它相关于比如 Iapp下载dlingT接口和抽象类的差异hreadPoolExecutor 之类来说是一个更优解,而且十分不幸的是,当由于协程被编译成状态机而被挂起时,IdlingThreadPoolExecutor 会认为线程池是闲暇的。

更多关于查验的信息appointment,请参阅 Hilt 查验攻略。

经过本文,您现已了解到怎样运用 Hi协程 线程lt 创APP建一个运用线程池作业原理等级的 CoroutineScope 作为依托项注入,怎样注入不同的 CoroutineDispatcher 实例,以及怎样在查验中替换它们的完毕。

欢迎您 点击这儿 向咱们提交反响,或同享您喜欢的内容、发现的问题。您的反响对咱们十分重要,感appear谢您的支撑!

发表评论

提供最优质的资源集合

立即查看 了解详情