한 글 은 Kotlin 의 협 정 을 철저히 이해 하 였 다.
비동기 스 레 드 를 해결 하기 위 한 리 턴 지옥
//
api.login(phone,psd).enquene(new Callback<User>(){
public void onSuccess(User user){
api.submitAddress(address).enquene(new Callback<Result>(){
public void onSuccess(Result result){
...
}
});
}
});
//
val user=api.login(phone,psd)
api.submitAddress(address)
...
협 정 이 뭐 예요?본질 적 으로 협 정 은 경량급 의 스 레 드 이다.
협정 키워드
val job = GlobalScope.launch {
delay(1000)
println("World World!")
}
CorotuneScope(역할 범위)GlobeScope,lifecycle Scope,view ModelScope 및 기타 사용자 정의 CoroutineScope 를 포함 하여 협회 코드 블록 이 실행 하 는 스 레 드,수명 주기 등 을 제어 합 니 다.
GlobeScope:전역 범위,자동 으로 실행 이 끝나 지 않 습 니 다.
lifecycle Scope:라 이 프 사이클 범위,activity 등 라 이 프 사이클 이 있 는 구성 요소 에 사용 되 며,DESTROYED 시 자동 으로 종 료 됩 니 다.추가 도입 이 필요 합 니 다.
viewModelScope:viewModel 범위,ViewModel 에 사용 되 며,ViewModel 이 회수 되 었 을 때 자동 으로 끝 납 니 다.추가 도입 이 필요 합 니 다.
작업(작업)
협 정의 계량 단 위 는 한 번 의 작업 임무 에 해당 합 니 다.launch 방법 은 기본적으로 새로운 Job 으로 돌아 갑 니 다.
suspend(걸 기)
방법 에 작용 하 는 것 은 이 방법 을 대표 하 는 시간 소모 임무 이다.예 를 들 어 위의 delay 방법 이다.
public suspend fun delay(timeMillis: Long) {
...
}
협정의 도입주 프레임 워 크($coroutinesversion 은 1.3.9 와 같은 최신 버 전 으로 바 뀌 었 습 니 다)
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
lifecycle Scope(선택 가능,버 전 2.2.0)
implementation 'androidx.activity:activity-ktx:$lifecycle_scope_version'
viewModelScope(선택 가능,버 전 2.3.0-beta 01)
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$coroutines_viewmodel_version"
간단히 사용 하 다먼저 간단 한 예 를 들다
lifecycleScope.launch {
delay(2000)
tvTest.text="Test"
}
위의 이 예 에서 실 현 된 기능 은 2 초 를 기다 린 다음 에 id 가 tvtest 인 TextView 컨트롤 의 text 값 을 Test 로 수정 하 는 것 입 니 다.사용자 정의 지연 반환 방법
kotlin 에 서 는 지연 이 있어 야 결 과 를 되 돌 릴 수 있 는 방법 에 대해 서 는 suspend 로 표시 해 야 합 니 다.
lifecycleScope.launch {
val text=getText()
tvTest.text = text
}
suspend fun getText():String{
delay(2000)
return "getText"
}
다른 스 레 드 에 서 는 Continuation 을 사용 하여 스 레 드 전환 이 필요 합 니 다.suspendCancellable Coroutine 또는 suspendCoroutine 패키지(전 자 는 취소 할 수 있 고 후자 의 확장 에 해당 합 니 다)를 사용 하여 it.resume()을 성공 적 으로 호출 하 였 으 며,it.resume With Exception()을 호출 하지 못 했 습 니 다.
suspend fun getTextInOtherThread() = suspendCancellableCoroutine<String> {
thread {
Thread.sleep(2000)
it.resume("getText")
}
}
이상 포획협정 안의 실 패 는 모두 이상 포획 을 통 해 특수 상황 을 통일 적 으로 처리 할 수 있다
lifecycleScope.launch {
try {
val text=getText()
tvTest.text = text
} catch (e:Exception){
e.printStackTrace()
}
}
취소 기능다음은 두 개의 job 를 실 행 했 습 니 다.첫 번 째 는 원본 입 니 다.두 번 째 는 1 초 후에 첫 번 째 job 를 취소 하면 tvText 의 텍스트 가 바 뀌 지 않 습 니 다.
val job = lifecycleScope.launch {
try {
val text=getText()
tvTest.text = text
} catch (e:Exception){
e.printStackTrace()
}
}
lifecycleScope.launch {
delay(1000)
job.cancel()
}
설정 시간 초과이것 은 시스템 이 자동 취소 기능 을 패키지 한 것 과 같 습 니 다.대응 함수 withTimeout
lifecycleScope.launch {
try {
withTimeout(1000) {
val text = getText()
tvTest.text = text
}
} catch (e:Exception){
e.printStackTrace()
}
}
반환 값 을 가 져 온 Joblaunch 와 유사 한 async 방법 이 있 습 니 다.Deferred 대상 을 되 돌려 줍 니 다.Job 의 확장 클래스 에 속 합 니 다.Deferred 는 되 돌아 오 는 결 과 를 얻 을 수 있 습 니 다.구체 적 으로 다음 과 같이 사용 합 니 다.
lifecycleScope.launch {
val one= async {
delay(1000)
return@async 1
}
val two= async {
delay(2000)
return@async 2
}
Log.i("scope test",(one.await()+two.await()).toString())
}
고급 진급사용자 정의 CorotuneScope
코 루 티 네 스 코 프 소스 부터 볼 게 요.
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
CoroutineScope 에는 주로 coroutineContext 대상 이 포함 되 어 있 습 니 다.coroutineContext 만 실현 하 는 get 방법 을 사용자 정의 해 야 합 니 다.
class TestScope() : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = TODO("Not yet implemented")
}
coroutine Context 를 만 들 려 면 먼저 Coroutine Context 가 무엇 인지 알 고 Coroutine Context 소스 코드 를 봐 야 합 니 다.
/**
* Persistent context for the coroutine. It is an indexed set of [Element] instances.
* An indexed set is a mix between a set and a map.
* Every element in this set has a unique [Key].
*/
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext =
...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext {
...
}
}
설명 을 통 해 우 리 는 그 본질 이 Element 를 포함 하 는 집합 이라는 것 을 알 고 있 습 니 다.set 와 map 집합 처럼 가 져 오기(get),접 기(fold,추가 와 교체 의 조합),상쇄(minusKey,제거),대상 조합(plus,예 를 들 어 val coroutineContext=coroutineContext 1+coroutineContext 2)을 실현 하지 않 았 습 니 다.그것 의 주요 내용 은 Element 이 고 Element 의 실현 은
Job 퀘 스 트
Continuation Interceptor 차단기
Job
SupervisorJob:부모 job 취소,모든 하위 job 취소
Dispatchers.Main:메 인 스 레 드 실행Dispatchers.IO:IO 스 레 드 실행라 이 프 사이클 스 코 프 와 유사 한 사용자 정의 TestScope 를 모 의 합 니 다.
class TestScope() : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = SupervisorJob() +Dispatchers.Main
}
여기 서 우 리 는 전체 프로 세 스 라인 SupervisorJob()과 구체 적 인 실행 환경 Dispatchers.Main(Android 메 인 스 레 드)을 정의 합 니 다.activity 의 lifecy cleScope 를 교체 하려 면 activity 에서 인 스 턴 스 를 만들어 야 합 니 다.
val testScope=TestScope()
그리고 activity 소각 시 모든 job 를 취소 합 니 다.
override fun onDestroy() {
testScope.cancel()
super.onDestroy()
}
다른 사용 방식 은 lifecycle Scope 와 같 습 니 다.
testScope.launch{
val text = getText()
tvTest.text = text
}
Job 을 깊이 이해 하 다CorotineScope 에는 주 Job 이 포함 되 어 있 습 니 다.그 후에 호출 된 launch 또는 다른 방법 으로 만 든 job 는 모두 CorotineScope 의 하위 Job 에 속 합 니 다.모든 job 는 자신 만 의 상태 가 있 습 니 다.그 중에서 isActive,isComplete,isCanceled,그리고 일부 기초 작업 start(),cancel(),join()을 포함 하고 구체 적 인 전환 절 차 는 다음 과 같 습 니 다.
우 리 는 먼저 job 를 만 드 는 것 부터 시작 합 니 다.launch 를 호출 할 때 기본적으로 세 개의 인자 가 있 습 니 다.
val job2= lifecycleScope.launch(start = CoroutineStart.LAZY) {
delay(2000)
Log.i("scope test","lazy")
}
job2.start()
이 모드 를 사용 하여 생 성 할 때 기본 값 은 new 상태 입 니 다.이때 isActive,isComplete,isCanceled 는 모두 false 입 니 다.start 를 호출 한 후에 active 상태 로 전환 합 니 다.그 중에서 isActive 만 true 이 고 작업 이 완료 되면 Completing 상태 에 들 어 갑 니 다.이 때 는 하위 job 가 완 료 될 때 까지 기다 리 는 상태 에서 isActive 만 true 입 니 다.모든 하위 job 도 완성 되면 Complete 상태 에 들 어가 고 isComplete 만 true 입 니 다.active 또는 Completing 상태 에서 취소 또는 이상 이 발생 하면 Cancelling 상태 에 들 어 갑 니 다.부모 job 와 다른 하위 job 를 취소 하려 면 취소 가 완 료 될 때 까지 기 다 립 니 다.이때 isCanceled 만 true 이 고 취소 가 완료 되면 Canceled 상태 에 들 어 갑 니 다.isCanceled 와 isComplete 는 모두 true 입 니 다.State
isActive
isCompleted
isCancelled
New
FALSE
FALSE
FALSE
Active
TRUE
FALSE
FALSE
Completing
TRUE
FALSE
FALSE
Cancelling
FALSE
FALSE
TRUE
Cancelled
FALSE
TRUE
TRUE
Completed
FALSE
TRUE
FALSE
서로 다른 job 상호작용 은 join()과 cancelAndJoin()을 사용 해 야 합 니 다.
join():현재 job 를 다른 협동 작업 에 추가 합 니 다
val job1= GlobleScope.launch(start = CoroutineStart.LAZY) {
delay(2000)
Log.i("scope test","job1")
}
lifecycleScope.launch {
job1.join()
delay(2000)
Log.i("scope test","job2")
}
suspend 깊이 이해suspend 는 kotlin 에 추 가 된 방법 수식어 로 서 최종 실현 은 자바 입 니 다.우 리 는 먼저 그들의 차이 점 을 봅 니 다.
suspend fun test1(){}
fun test2(){}
대응 자바 코드
public final Object test1(@NotNull Continuation $completion) {
return Unit.INSTANCE;
}
public final void test2() {
}
대응 바이트 코드
public final test1(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
...
L0
LINENUMBER 6 L0
GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
ARETURN
L1
LOCALVARIABLE this Lcom/lieni/android_c/ui/test/TestActivity; L0 L1 0
LOCALVARIABLE $completion Lkotlin/coroutines/Continuation; L0 L1 1
MAXSTACK = 1
MAXLOCALS = 2
public final test2()V
L0
LINENUMBER 9 L0
RETURN
L1
LOCALVARIABLE this Lcom/lieni/android_c/ui/test/TestActivity; L0 L1 0
MAXSTACK = 0
MAXLOCALS = 1
이 를 통 해 알 수 있 듯 이 suspend 를 추가 하 는 방법 은 사실 일반적인 방법 과 마찬가지 로 들 어 올 때 Continuation 대상 이 하나 더 생 겨 서 Unit.INSTANCE 대상 으로 돌 아 왔 을 뿐이다.
public interface Continuation<in T> {
public val context: CoroutineContext
public fun resumeWith(result: Result<T>)
}
Continuation 의 구체 적 인 실현 은 BaseContinuation Impl 에서
internal abstract class BaseContinuationImpl(...) : Continuation<Any?>, CoroutineStackFrame, Serializable {
public final override fun resumeWith(result: Result<Any?>) {
...
while (true) {
...
with(current) {
val outcome = invokeSuspend(param)
...
releaseIntercepted()
if (completion is BaseContinuationImpl) {
...
} else {
...
return
}
}
}
}
...
}
resume With 를 호출 할 때 invoke Suspend(param)와 releaseIntercepted()를 호출 하여 최상 위 completion 이 실 행 될 때 까지 순환 을 실행 하고 협 정 된 interceptor 를 방출 합 니 다.최종 석방 은 Continuation Impl 에서 이 루어 집 니 다.
internal abstract class ContinuationImpl(...) : BaseContinuationImpl(completion) {
...
protected override fun releaseIntercepted() {
val intercepted = intercepted
if (intercepted != null && intercepted !== this) {
context[ContinuationInterceptor]!!.releaseInterceptedContinuation(intercepted)
}
this.intercepted = CompletedContinuation
}
}
이 를 통 해 알 수 있 듯 이 방출 은 최종 적 으로 CoroutineContext 에서 Continuation Interceptor 의 Element 를 통 해 이 루어 집 니 다.일시 정지 도 마찬가지다.
public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineUninterceptedOrReturn { c: Continuation<T> ->
val safe = SafeContinuation(c.intercepted())
...
}
기본적으로 Continuation 의 intercepted()방법 을 호출 합 니 다.
internal abstract class ContinuationImpl(...) : BaseContinuationImpl(completion) {
...
public fun intercepted(): Continuation<Any?> =intercepted
?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this)
.also { intercepted = it }
}
일시 정지 가 최종 적 으로 CorotineContext 에서 Continuation Interceptor 를 위 한 Element 를 통 해 이 루어 지 는 것 을 볼 수 있 습 니 다.프로 세 스 요약(스 레 드 전환)
새로운 Continuation 을 만 듭 니 다
CoroutineScope 는 기본적으로 현재 스 레 드 를 막 지 않 습 니 다.차단 이 필요 하 다 면 runBlocking 을 사용 할 수 있 습 니 다.메 인 스 레 드 에서 아래 코드 를 실행 하면 2s 화이트 스크린 이 나타 납 니 다.
runBlocking {
delay(2000)
Log.i("scope test","runBlocking is completed")
}
차단 원리:runBlocking 을 실행 하면 기본적으로 BlockingCorotine 을 만 들 고 BlockingCorotine 에 서 는 현재 Job 이 isComplete 상태 일 때 까지 순환 을 실행 합 니 다.
public fun <T> runBlocking(...): T {
...
val coroutine = BlockingCoroutine<T>(newContext, currentThread, eventLoop)
coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
return coroutine.joinBlocking()
}
private class BlockingCoroutine<T>(...) : AbstractCoroutine<T>(parentContext, true) {
...
fun joinBlocking(): T {
...
while (true) {
...
if (isCompleted) break
...
}
...
}
}
총결산여기 서 Kotlin 중 협 정 을 철저히 이해 하 는 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 Kotlin 협 정 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 실험, 에피소드 1a String 의 중심에 있는 문자를 반환하는 메서드를 작성하려는 경우 Java에서 가장 좋은 옵션은 유틸리티 클래스를 정의하는 것입니다. Kotlin을 사용하면 을 통해 기존 클래스에 새 메서드를 추가할 수 있습...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.