【问题标题】:Kotlin coroutine scope & job cancellation in non-lifecycle classes非生命周期类中的 Kotlin 协程范围和作业取消
【发布时间】:2019-05-28 10:54:52
【问题描述】:

如何在没有生命周期的类(如存储库)中使用新的 Kotlin v1.3 协程? 我有一个类,我检查缓存是否过期,然后决定是从远程 API 还是本地数据库中获取数据。我需要从那里启动launchasync。但是我该如何取消作业呢?

示例代码:

class NotesRepositoryImpl @Inject constructor(
     private val cache: CacheDataSource,
     private val remote: RemoteDataSource
 ) : NotesRepository, CoroutineScope {

private val expirationInterval = 60 * 10 * 1000L /* 10 mins */
private val job = Job()
override val coroutineContext: CoroutineContext
    get() = Dispatchers.IO + job

override fun getNotes(): LiveData<List<Note>> {
    if (isOnline() && isCacheExpired()) {
        remote.getNotes(object : GetNotesCallback {
            override fun onGetNotes(data: List<Note>?) {
                data?.let {
                    launch {
                        cache.saveAllNotes(it)
                        cache.setLastCacheTime(System.currentTimeMillis())
                    }
                }
            }
        })
    }
    return cache.getNotes()
}

override fun addNote(note: Note) {
    if (isOnline()) {
        remote.createNote(note, object : CreateNoteCallback {
            override fun onCreateNote(note: Note?) {
                note?.let { launch { cache.addNote(it) } }
            }
        })
    } else {
        launch { cache.addNote(note) }
    }
}

override fun getSingleNote(id: Int): LiveData<Note> {
    if (isOnline()) {
        val liveData: MutableLiveData<Note> = MutableLiveData()
        remote.getNote(id, object : GetSingleNoteCallback {
            override fun onGetSingleNote(note: Note?) {
                note?.let {
                    liveData.value = it
                }
            }
        })
        return liveData
    }
    return cache.getSingleNote(id)
}

override fun editNote(note: Note) {
    if (isOnline()) {
        remote.updateNote(note, object : UpdateNoteCallback {
            override fun onUpdateNote(note: Note?) {
                note?.let { launch { cache.editNote(note) } }
            }
        })
    } else {
        cache.editNote(note)
    }
}

override fun delete(note: Note) {
    if (isOnline()) {
        remote.deleteNote(note.id!!, object : DeleteNoteCallback {
            override fun onDeleteNote(noteId: Int?) {
                noteId?.let { launch { cache.delete(note) } }
            }
        })
    } else {
        cache.delete(note)
    }
}

private fun isCacheExpired(): Boolean {
    var delta = 0L
    runBlocking(Dispatchers.IO) {
        val currentTime = System.currentTimeMillis()
        val lastCacheTime = async { cache.getLastCacheTime() }
        delta = currentTime - lastCacheTime.await()
    }
    Timber.d("delta: $delta")
    return delta > expirationInterval
}

private fun isOnline(): Boolean {
    val runtime = Runtime.getRuntime()
    try {
        val ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8")
        val exitValue = ipProcess.waitFor()
        return exitValue == 0
    } catch (e: IOException) {
        e.printStackTrace()
    } catch (e: InterruptedException) {
        e.printStackTrace()
    }
    return false
}

}

【问题讨论】:

    标签: android kotlin kotlin-coroutines coroutine coroutinescope


    【解决方案1】:

    您可以在存储库中创建一些取消方法,并从具有生命周期的类(Activity、Presenter 或 ViewModel)中调用它,例如:

    class NotesRepositoryImpl @Inject constructor(
         private val cache: CacheDataSource,
         private val remote: RemoteDataSource
    ) : NotesRepository, CoroutineScope {
    
        private val job = Job()
        override val coroutineContext: CoroutineContext
            get() = Dispatchers.IO + job
    
        fun cancel() {
            job.cancel()
        }
    
        //...
    
    }
    
    class SomePresenter(val repo: NotesRepository) {
    
        fun detachView() {
            repo.cancel()
        }
    }
    

    或者将启动协程移动到具有生命周期的某个类。

    【讨论】:

    • 如果我在 Repository 和生命周期感知类之间有更多层怎么办?
    • 我会在每一层创建额外的取消方法,传播对存储库的调用。
    猜你喜欢
    • 2019-12-11
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多