오늘은 Android Studio의 strings.xml에 저장해놓은 문자열을 어떻게 사용할 수 있을지 정리해보겠다!
앱 내에서 사용되는 문자열을 strings.xml에 미리 저장해놓으면 중복되는 텍스트를 쉽게 관리할 수 있고, 하드코딩도 줄일 수 있다는 장점이 있다. 그렇지만 어정쩡하게 활용하면 안하느니만 못할 수 있다. 문자열 안에 변수를 어떻게 넣고, 데이터바인딩을 어떻게 적용할 수 있을지까지 다뤄보겠다.
프로젝트에서의 문자열 관리 예시
<string name="next_btn">다음</string>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/route_create_next_btn"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="@string/next_btn"
android:layout_marginHorizontal="20dp"
android:layout_marginBottom="28dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
style="@style/default_large_button"/>
가장 기본적으로는 TextView, Button 등 텍스트가 들어갈 수 있는 위젯에
android:text="@string/next_btn"
식으로 미리 저장된 리소스를 넣을 수 있다!
이 이후에 작성되는 레이아웃 코드에서는, 편의상 텍스트를 지정하는 부분을 android:text="@string/next_btn"
식으로만 표시하도록 하겠다. 택스트가 들어갈 수 있는 위젯에 모두 공통적으로 쓰일 수 있음을 의미한다고 생각해주면 좋겠다.
타 프로그래밍 언어에서 문자열 내에 변수를 넣어 출력하고 싶을 때 Int 형식이면 %d, 문자열 형식이면 %s 등으로 표시하는 걸 본 적 있을 것이다. 이와 유사한 개념으로 보면 된다. strings.xml
에 문자열을 미리 넣어둘 때도 %d, %s 등으로 변수가 들어갈 자리를 지정할 수 있다.
<string name="search_route_result_title">\'%s\' 루트</string>
<string name="filter_look_route">%d개 루트 보기</string>
여기에서 %s
, %d
자리에 문자열을 넣어줄 수 있다.
android:text="@{@string/search_route_result_title(`hi`)}"
android:text="@{@string/filter_look_route(111)}"
** 문자열(%s)의 경우: xml 안에서는 큰 따옴표(")나 작은 따옴표(')가 안 먹기 때문에, 문자열을 꼭`로 감싸서 사용해야 함.
그치만! 이것 또한 하드코딩과 별다를 바 없기 때문에 보통은 데이터바인딩과 함께 사용한다. (<- 사용자가 입력한 데이터나, 서버에서 받아온 정보를 받아서 텍스트에 보여주기가 용이함)
%s 자리에 문자열 'hi'가 들어감 | %d 자리에 정수 111이 들어감 |
---|
android:text="@{@string/search_route_result_title(viewModel.routeSearchKeyWord)}"
android:text="@{@string/filter_look_route(viewModel.searchResultNum)}"
레이아웃의 xml 파일에서 미리 variable를 정의하고, 이를 활용해 텍스트에 변수를 전달할 수 있다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.daval.routebox.presentation.ui.seek.search.FilterViewModel" />
</data>
</layout>
참고로 뷰모델에서는 변수가 아래와 같이 정의되어 있다.
routeSearchKeyWord
@HiltViewModel
class SearchViewModel @Inject constructor(
val repository: SeekRepository
): ViewModel() {
private val _routeSearchKeyWord = MutableLiveData<String>("") // 검색 결과 타이틀 입력용
val routeSearchKeyWord: LiveData<String> = _routeSearchKeyWord
val searchWord = MutableLiveData<String>("") // 사용자가 입력한 검색어
// 루트 검색
fun inputRouteSearchWord() {
Log.d("SearchViewModel", "입력한 검색어: ${searchWord.value}")
// 검색 결과 수정
_routeSearchKeyWord.value = searchWord.value
// 루트 검색 결과 조회
viewModelScope.launch {
_searchResultRoutes.value = repository.searchRoute(
searchWord = searchWord.value!!,
sortBy = _selectedOrderOption.value!!.serverEnum,
// ...
)
}
}
}
searchWord는 EditText와 양방향 바인딩이 걸려있는 변수이고, 이 EditText에 입력한 검색어를 '검색 버튼을 누르면' 조회를 진행하기 때문에 버튼 클릭 후의 텍스트를 저장하기 위해 routeSearchKeyWord를 사용했다.
searchResultNum
@HiltViewModel
class FilterViewModel @Inject constructor(
val repository: SeekRepository
): ViewModel() {
// 필터링을 적용한 검색 결과 개수
private val _searchResultNum = MutableLiveData<Int>(0)
val searchResultNum: LiveData<Int> = _searchResultNum
// 루트를 조회해서 결과 개수 확인
fun inquirySearchResultNum() {
Log.d("FilterViewModel", "받아온 검색어: $searchWord")
viewModelScope.launch {
_searchResultNum.value = repository.searchRoute(
searchWord = searchWord,
sortBy = OrderOptionType.ORDER_RECENT.serverEnum,
// ...
).size
}
}
}
%s 자리에 뷰모델의 routeSearchKeyWord가 들어감 | %d 자리에 뷰모델의 searchResultNum이 들어감 |
---|
변수가 여러개인 경우에는 그냥 콤마(,)로 구분해준다.
<string name="weather_update_date">%s %s 업데이트\n제공: 기상청</string>
android:text="@{@string/weather_update_date(date, time)}"
괄호 안에 들어갈 변수를 순서대로 넣어주면 된다.
Activity나 Fragment 코드에서 사용할 수 있는 방법이다.
<다양한 예시 참고>
🔗 [Android/Kotlin] 안드로이드 스튜디오에서 JDBC를 이용해 MySQL 연동하기 (3/3) - 통신편
기본적으로 strings.xml 코드를 불러오는 방식은
resources.getString(R.string.db_url)
형태이다.
텍스트로 넣어주고 싶다면
binding.nextBtn.text = ContextCompat.getString(this, R.string.next_btn)
식으로 넣어줄 수 있다.
strings.xml 파일에서 문자열 작성 방법은 xml에서 한 것과 동일하다.
<string name="signup_complete">%s,\n루트박스에 온 걸 환영해요!</string>
%s 자리에 회원가입 시에 작성한 유저의 닉네임을 넣어주면 된다. 하드코딩할 경우, 아래와 같이 작성할 수 있다.
binding.termTitle.text = String.format(resources.getString(R.string.signup_complete), "코코아")
변수를 넣어줘야 하는 경우
String.format({resources.getString({리소스_id}), {넘겨줄 값})
식으로 작성해줄 수 있다.
위와 같은 동일한 string 리소스에서 하드 코딩 대신 뷰모델에서 사용한 변수를 전달할 수 있다.
binding.termTitle.text = String.format(resources.getString(R.string.signup_complete), viewModel.nickname.value)
strings.xml 파일 작성은 마찬가지로 앞선 xml에서와 동일하다. 이번엔 3개를 넣어 본다고 하자.
// 팔로워, 팔로잉 목록 조회
<string name="query_select_follow_list">SELECT user_id, user_name, name, profileImage_url FROM user WHERE user_id IN (SELECT %1$s FROM %2$s WHERE user_id = %3$d)</string>
%1$1
,%2$s
,%3%d
식으로 변수가 들어갈 순서도 지정해 줄 수 있다.
String.format(resources.getString(R.string.query_select_follow_list), targetId, table, userId)