본문 바로가기

안드로이드

context receivers - 확장함수의 확장함수?

반응형

컴포즈에서는 특정 영역에서만 호출할 수 있는 함수 형태를 많이 사용한다.
 

예를 들면 BoxScope, ColumnScope, RowScope 등의 영역 안에서만 호출할 수 있는
Modifier.align, Modifier.weight 등이 있다.

 
확장함수를 통해서 해당 영역에서만 사용할 함수들을 추가할 수 도 있는데,
문제가 있다.

interface CustomScope {
    val value: Int

    fun Modifier.scopeModifier(): Modifier
}

// 불가능
fun CustomScope.Modifier.newScopeModifier(): Modifier {
    return this
}

CustomScope 같은 영역에다가 새로운 Modifier를 추가하고 싶을 때,
확장함수에다가 또 확장함수는 붙일수가 없다.

interface ModifiedCustomScope : CustomScope {
    fun Modifier.newScopeModifier(): Modifier
}

class ModifiedCustomScopeImpl(customScope: CustomScope) : ModifiedCustomScope , CustomScope by customScope{
    override fun Modifier.newScopeModifier(): Modifier {
        return this
    }
}

CustomScope 가 내가 가지고 있는 코드라면 CustomScope 안에다가 Modifier를 추가하면 되지만
BoxScope, ColumnScope 같이 라이브러리에 포함되어 있는 형태라면
결국 새로운 Modifier 하나를 추가하기 위해 Scope 를 상속받는 새로운 Scope를 만들고,
delegation을 통해서 이전의 Scope도 연결해줘야 한다.

context receivers 사용하기

kotlinOptions {
    jvmTarget = '1.8'
    freeCompilerArgs = ["-Xcontext-receivers"]
}

gradle에 명시하여 활성화할 수 있다.
 
context receivers는 함수에다가 적용시킬 수 있고,
적용된 함수는 해당 context 내에서만 호출할 수 있도록 제한을 걸어준다.
 
이걸 이용하면 위의 문제를 해결할 수 있다.

interface CustomScope {
    val value: Int

    fun Modifier.scopeModifier(): Modifier
}

context(CustomScope)
fun Modifier.contextModifier(): Modifier {
    Log.d("D000l", value.toString())
    return this
}

context 를 이용하면 해당 함수가 CustomScope 안에서만 사용할 수 있도록 제한된다.

CustomScope에 있는 값도 바로 접근하는 것이 가능하다.
 

this로 접근이 필요한 경우 this@CustomScope 처럼 가능하다.
(타이핑시에 this@CustomScope는 자동 완성이 안된다. 아직 실험기능이라 그런 듯 )

context(Context, Int)
fun getStringFromStringRes(){
    this@Context.getString(this@Int)
}

val appName = with(R.string.app_name){
    getStringFromStringRes()
}

여러 개의 context를 적용할 수도 있기 때문에 확장함수로 풀어내기 애매했던 부분들에 유용하게 사용할 수 있다.

반응형