我正在为 jvm 设置一个基于 kotlin 协程的网络框架。Client 和 Server 类实现 CoroutineScope,并且 coroutinecontext 的覆盖是 Dispatchers.IO,因为我非常确定这是用于这种情况的正确 Dispatcher。但是,我希望在主线程上处理读取数据包,或者至少提供该选项。在没有阅读文档的情况下,我使用了 Dispatchers.Main,我现在意识到它是针对 android UI 线程的。是否有一个调度程序可以用来让协程在主线程上运行?如果没有,我该如何制作呢?
我查看了 kotlin 文档,了解如何创建基于单个线程的调度程序,但除了创建新线程的 newSingleThreadContext 之外,我找不到任何内容。我还发现可以从 java 执行器创建调度程序,但我仍然不确定如何将其限制为已经存在的线程。
class AbstractNetworkComponent : CoroutineScope {
private val packetProcessor = PacketProcessor()
private val job = Job()
override val coroutineContext = job + Dispatchers.IO
}
class PacketProcessor : CoroutineScope {
private val job = Job()
override val coroutineContext = job + Dispatchers.Main //Android only!
private val packetHandlers = mutableMapOf<Opcode, PacketHandlerFunc>()
fun handlePacket(opcode: Opcode, packet: ReceivablePacket, networker: Writable) { …Run Code Online (Sandbox Code Playgroud) 我有一个场景,我的代码必须发送 api 调用并继续其工作(其中包含另一个 api 调用),而不等待第一次调用的结果。
现在我在我的视图模型中执行此操作
fun showItem(id:Int) {
launch{
repo.markItemRead(id)
}
launch {
try {
val item = repo.getItemById(id).getOrThrow
commands.postValue(ShowItemCommand(item))
} catch (t:Throwable) {
commands.postValue(ShowError(R.string.error_retrieve_item))
repo.logError(t)
}
}
}
Run Code Online (Sandbox Code Playgroud)
这调用了具有这两个功能的存储库
suspend fun markItemRead(id) {
try {
service.markItemAsRead(id)
} catch(ignored:Throwable) {
}
}
suspend fun getItemById(id) : Result<ItemData> {
return try {
val response : ItemEntity = service.getItemById(id)
val item = response.toData()
Result.Success(item)
} catch (t:Throwable) {
Result.Failure(t)
}
}
Run Code Online (Sandbox Code Playgroud)
如果存储库完成所有这些工作,我会更喜欢它,因为每次都必须遵循另一项工作。
不幸的是,当我尝试在我的存储库中执行类似的操作时:
suspend fun getItemById(id:Int) : Result<ItemData> {
try { …Run Code Online (Sandbox Code Playgroud) 我想知道coroutineScope工作完成后是否会自动取消。coroutineScope假设我在自定义类中创建一个而不是 ViewModel类或Fragment / Activity类:
class MyClass {
private val backgroundScope = CoroutineScope(Dispatchers.Default)
fun doSomething() = backgroundScope.launch {
//do background work
}
}
Run Code Online (Sandbox Code Playgroud)
那么,后台工作完成后,会backgroundScope自动取消吗?
android kotlin kotlin-coroutines android-threading coroutinescope
在 Kotlin 中启动协程有多种方法。我发现了几个使用GlobalScope和的例子CoroutineScope。但后一个是在启动协程时直接创建的:
使用GlobalScope:
fun loadConfiguration() {
GlobalScope.launch(Dispatchers.Main) {
val config = fetchConfigFromServer() // network request
updateConfiguration(config)
}
}
Run Code Online (Sandbox Code Playgroud)
使用CoroutineScope实例,在启动协程时直接创建:
fun loadConfiguration() {
CoroutineScope(Dispatchers.Main).launch {
val config = fetchConfigFromServer() // network request
updateConfiguration(config)
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,这两种方法有区别吗?
第二种情况不是违反了结构化并发的原则吗?
android kotlin kotlin-coroutines coroutinescope structured-concurrency
我无法理解内存管理如何在 Android 上与本地创建的协程一起工作。这是一些代码:
init {
CoroutineScope(Dispatchers.Default).launch {
val result = workerA.runSuspended(paramA)
liveDataA.postValue(result)
}
}
Run Code Online (Sandbox Code Playgroud)
对于短暂的挂起函数调用,我想启动一次协程,然后我不再需要作用域。我知道这样写时不能取消范围。但我的主要问题是:
在 kotlin coroutines doc 中,它解释了“runBlocking 和 coroutineScope 之间的区别”:
范围生成器
除了不同构建器提供的协程作用域之外,还可以使用 coroutineScope 构建器来声明您自己的作用域。它创建了一个协程范围,并且在所有启动的子项完成之前不会完成。
The main difference between runBlocking and coroutineScope is that the latter does not block the current thread while waiting for all children to complete.
我不太明白,示例代码显示
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
launch {
delay(200L)
println("+++Task from runBlocking")
}
coroutineScope { // Creates a coroutine scope
launch {
delay(500L)
println("+++Task from nested launch")
}
delay(100L)
println("+++ Task from coroutine scope") // This line …Run Code Online (Sandbox Code Playgroud) 是在 ViewModel 中启动协程更好,还是用suspend修饰符标记 ViewModel 函数并在 Activity/fragment 本身中启动协程更好?
在 ViewModel 中启动:
class MainViewModel: ViewModel() {
fun addNewItem(item: Item) {
viewModelScope.launch {
// Add the item to database
}
}
}
Run Code Online (Sandbox Code Playgroud)
class ItemsFragment: Fragment() {
fun onButtonClick() {
viewModel.addNewItem(Item())
}
}
Run Code Online (Sandbox Code Playgroud)
在 LifeCycleOwner 中启动:
class MainViewModel: ViewModel() {
suspend fun addNewItem(item: Item) {
// Add the item to database
}
}
Run Code Online (Sandbox Code Playgroud)
class ItemsFragment: Fragment() {
fun onButtonClick() {
lifecycleScope.launchWhenStarted {
viewModel.addNewItem(Item())
}
}
}
Run Code Online (Sandbox Code Playgroud) android kotlin android-viewmodel kotlin-coroutines coroutinescope
尝试使用 room api 并且必须处理异步任务,你知道为什么。我选择了 kotlin 协程和 androidx.lifecycle。尝试编写一些代码并在 IDE 中显示 2 个错误
无法访问“kotlinx.coroutines.CoroutineScope”,它是“androidx.lifecycle.LifecycleCoroutineScope”的超类型。检查模块类路径是否缺少或冲突的依赖项无法访问类“kotlinx.coroutines.Job”。检查模块类路径是否存在缺少或冲突的依赖项 错误
这是我的 gradle 模块
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
android {
compileSdk 31
defaultConfig {
applicationId "com.jacksafblaze.sqlitedemo"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures{
viewBinding true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "androidx.room:room-ktx:2.3.0"
implementation "androidx.room:room-runtime:2.3.0"
kapt …Run Code Online (Sandbox Code Playgroud) kotlin android-studio android-gradle-plugin kotlin-coroutines coroutinescope
下面的完全一样吗?
\nlifecycleScope.launch {\n\xc2\xa0 whenStarted { \n // Do something\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n和
\nlifecycleScope.launchWhenStarted {\n // Do something\n}\nRun Code Online (Sandbox Code Playgroud)\n或者它们确实有一些不同的目的,因此提供了这两个 API?
\n我有以下代码(伪代码)
fun onMapReady()
{
//do some stuff on current thread (main thread)
//get data from server
GlobalScope.launch(Dispatchers.IO){
getDataFromServer { result->
//update UI on main thread
launch(Dispatchers.Main){
updateUI(result) //BREAKPOINT HERE NEVER CALLED
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如评论所述,代码永远不会进入协程调度到主队列。但是,如果我明确使用GlobalScope.launch(Dispatchers.Main)而不是仅仅使用以下内容,则以下内容有效launch(Dispatchers.Main)
fun onMapReady()
{
//do some stuff on current thread (main thread)
//get data from server
GlobalScope.launch(Dispatchers.IO){
getDataFromServer { result->
//update UI on main thread
GlobalScope.launch(Dispatchers.Main){
updateUI(result) //BREAKPOINT HERE IS CALLED
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
为什么第一种方法不起作用?