strings.xml이란?
strings.xml은 문자열 key값에 대한 value값을 매핑해놓은 XML파일이다.
XML파일이란 eXtensible Markup Language 의 약자로 다목적 마크업 언어이다. 안드로이드에서는 이 xml파일을 <resource> 블록 내에 리소스 태그을 만드는 식으로 사용한다. 예를 들어 문자열의 경우 <string> 태그를 이용해 정의한다.
예를 들어 아래와 같은 strings.xml 파일이 있다고 해보자.
위 string.xml 파일은 아래 두가지 Key-Value 쌍을 가지고 있다. 하나는 "app_name" - "Compose" 쌍이고, 다른 하나는 "kotlin_world_blog"와 "Kotlin World Blog" 쌍이다.
Key | Value |
app_name | Compose |
kotlin_world_blog | Kotlin World Blog |
이 값들은 안드로이드 내부에서 문자열을 표기하기 위해 사용된다. 자 이 값들을 어떻게 로딩하는지 아래에서 살펴보자.
Compose 이전의 UI를 위한 문자열 로딩 방식
Compose가 출시되기 이전의 안드로이드에서는 Kotlin 코드 상에서 문자열을 로딩하기 위해서는 context의 getString 메서드를 이용해서만 가능했다. 하지만, 이 방식은 context 속의 resource가 있어야 로딩이 가능해 context에 대한 관리가 별도로 필요했다.
Context에는 두가지 종류가 있다. Activity에서 관리되는 baseContext와 Application에서 관리되는 applicationContext이다. 이 둘 중 하나가 있어야 내부의 resource에 접근하여 String Resource 로딩이 가능했다. 하지만, 이 Context는 많은 정보를 담고 있는 객체로 관리를 잘못할 경우 메모리 누수가 일어나기 쉽다.
특히 context를 WeakReference 처리하지 않고 문자열이 필요한 외부로 넘길 경우 memory leak이 발생할 우려도 있어 관리가 쉽지 않았다. 잘못하면 문자열을 로딩하다가 앱이 죽어버리거나, 앱에서 메모리가 누수되는 문제가 생기는 것이다.
물론 layout xml파일에서 로딩할 경우 직접 단순히 문자열 리소스의 Key값 만으로 접근이 가능했지만, 가변적인 문자열이 적용되어야 하는 곳에서는 context를 이용한 문자열 로딩 방식이 필수적이었다.
stringResource를 이용한 문자열 로딩
Compose에서는 위의 context를 직접 이용한 문자열 로딩 문제를 아주 우아한 방법으로 해결한다. UI에서만 사용되는 문자열 로딩 방식. 즉, @Composable 을 위한 별도의 문자열 로딩 메서드인 stringResource 메서드를 제공한다.
@Composable
@ReadOnlyComposable
fun stringResource(@StringRes id: Int): String {
val resources = resources()
return resources.getString(id)
}
stringResource 함수의 resource 객체를 가져오는 resources() 메서드에서는 Composable이 불리는 위치의 context를 이용해 문자열을 로딩한다. 쉽게 말하면 Compose 프레임웍단에서 문자열 로딩을 위한 Context를 관리해주는 방식으로 바뀌어 개발자들은 어떤 Context를 사용하는지 생각할 필요가 없어졌다.
@Composable
@ReadOnlyComposable
private fun resources(): Resources {
LocalConfiguration.current
return LocalContext.current.resources
}
이제는 어느 @Composable 에서나 stringResource를 이용해 문자열을 로딩할 수 있게 되었다
Composable 외부에서의 string 리소스 로드
물론 @Composable 외부에서는 stringResource를 사용할 수 없다. 만약 사용하려고 하면 다음과 같은 오류가 뜬다.
@Composable invocations can only happen from the context of a @Composable function
위 메세지를 번역하면 stringResource는 Composable 내부에서만 사용할 수 있는 function이라는 것이다.
따라서 Composable 외부에서 String Resource를 로딩하려면 여전히 아래와 같이 Context의 getString 함수를 써야 한다.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
..
baseContext.getString(R.string.kotlin_world_blog)
applicationContext.getString(R.string.kotlin_world_blog)
..
}
}