
xml 작성 시 앞에 android:와 app:의 차이는 android는 옛날부터 있던 요소이고 app은 이후에 추가된 요소다.
android와 app 둘다 있는 속성인 경우에는 app인 속성으로 선택하면 된다.
tools 요소(스패너 아이콘모양)는 미리보기에서만 표시되고 실제 어플 화면에서는 보이지 않음(테스트용)
모든 값들은 xml에 작성하고 이것들을 불러오는 방식으로 작업하기
(언어, 해상도 등)
R.class를 확인해보면 res폴더에 추가되는 모든 리소스에 정수값을 자동으로 할당하여 관리하고 있음
어떤 파일이나 값을 관리하기 위해 부여한 정수값을 리소스id라고 부름
파일 :
리소스 : 이미지, 사운드, 동영상, 동작 데이터, 텍스쳐 데이터, 모델링 데이터, 맵 데이터 등등... 어플리케이션 실행에 필요한 데이터가 담겨져 있는 파일. 데이터를 읽어오기만 하는 용도로 사용한다.

안드로이드의 저장 방식 중 하나로 애플리케이션의 데이터를 간단하게 저장할 수 있는 수단
많은 양의 데이터는 SQLite, 소규모의 데이터는 Preferences를 사용하면 된다.
애플리케이션 설정 데이터와 같이 유일한 데이터들을 기록할 때 Prefrences를 사용한다.
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
activityMainBinding.apply {
button.setOnClickListener {
// Preferences 객체를 추출한다.
// 첫 번째 : Preferences의 이름(자유롭게). 없으면 새로 생성해준다.
// 두 번째 : MODE_APPEND - 데이터를 저장할 때 사용한 이름의 데이터가 있어도 추가적으로 저장한다.
// MODE_PRIVATE - 데이터를 저장할 때 사용한 이름의 데이터가 있으면 덮어씌워준다.
val pref = getSharedPreferences("data", Context.MODE_PRIVATE)
// 데이터를 저장하기 위한 객체를 추출한다.
val editor = pref.edit()
// editor 객체에 값을 담는다. (6가지 타입만 가능)
editor.putBoolean("data1", true)
editor.putFloat("data2", 11.11f)
editor.putInt("data3", 100)
editor.putLong("data4", 200L)
editor.putString("data5", "문자열 데이터")
val set1 = mutableSetOf<String>()
set1.add("문자열1")
set1.add("문자열2")
set1.add("문자열3")
editor.putStringSet("data6", set1)
// 담겨진 값을 저장한다.
// commit과 apply가 있는데 옛날에는 commit을 썼고 지금은 apply를 쓴다.
// apply는 람다식을 추가로 사용할 수 있음
editor.apply()
textView.text = "저장되었습니다."
}
button2.setOnClickListener {
val pref = getSharedPreferences("data", Context.MODE_PRIVATE)
// 저장한 데이터를 가져온다.
// 두번째 매개변수에는 기본값을 설정할 수 있다.
// 지정된 이름으로 저장된 데이터가 없는 경우에는
// 두번째 매개변수로 지정한 기본값이 반환되어 변수에 담긴다.
// getString과 getStringset 기본값으로 null을 받을 수 있다.
val data1 = pref.getBoolean("data1",false)
val data2 = pref.getFloat("data2",0.0f)
val data3 = pref.getInt("data3",0)
val data4 = pref.getLong("data4",0L)
val data5 = pref.getString("data5",null)
val data6 = pref.getStringSet("data6",null)
textView.apply {
text = "data1 : ${data1}\n"
append("data2 : ${data2}\n")
append("data3 : ${data3}\n")
append("data4 : ${data4}\n")
if(data5 != null){
append("data5 : ${data5}\n")
}
if(data6 != null){
data6.forEach {
append("data6 : ${it}\n")
}
}
}
}
}
}
}

*set의 순서는 저장한 순서와 일치하지 않는다.
UI를 통해서 Preferences를 사용할 수 있도록 제공되는 개념
PreferenceFragement를 사용하며 저장 기능까지 모두 구현되어 있다.




옛날에는 Ringtone이 있었으나 현재는 5가지만 세팅 가능
build.gradle.kts에 implementation("androidx.preference:preference-ktx:1.2.1") 추가
Sync now도 눌러주기
// build.gradle.kts
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
implementation("androidx.preference:preference-ktx:1.2.1")
}
라이브러리를 추가해줘야 SettingFragment클래스에 PreferenceFragmentCompat을 상속할 수 있다.
// SettingFragment.kt
// build.gradle 에 androidx.preference:perference 라이브러리를 추가한다.
class SettingFragment : PreferenceFragmentCompat() {
// rootKey : Preference의 이름
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
// xml 폴더에 있는 preference xml 파일을 지정해준다.
setPreferencesFromResource(R.xml.pref, rootKey)
}
}
pref.xml 세팅
Preference 요소들을 그룹으로 묶어주는 역할을 한다. 특별한 기능은 없다.
title - 그룹에 표시할 문자열
문자열 입력
defaultValue : 초기값
title : 화면에 보여지는 이름
key : 데이터를 가져올 때 사용하는 이름
summary : 표시하고자 하는 설명
icon : 좌측에 표시될 아이콘
dialogIcon : 입력을 위해 뜨는 다이얼로그의 아이콘
dialogTitle : 입력을 위해 뜨는 다이얼로그의 타이틀
dialogMessage : 입력을 위해 뜨는 다이얼로그의 메시지
<PreferenceCategory android:title="입력요소">
<EditTextPreference
android:defaultValue="안녕하세요"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="문자열 입력"
app:dialogIcon="@drawable/add_24px"
app:dialogMessage="문자열 입력 요소 입니다."
app:dialogTitle="문자열 입력"
app:icon="@drawable/approval_24px"
app:key="data1"
app:summary="문자열 입력 요소 입니다." />
</PreferenceCategory>



defaultValue : 초기값
key : 데이터를 가져올 때 사용하는 이름
title : 화면에 보여지는 이름
summary : 표시되는 설명
icon : 좌측에 표시되는 아이콘
summary : 표시하고자 하는 설명
summaryOff : 체크가 해제 되어 있을 때 보여줄 설명 문자열. 설정되어 있지 않으면 summary 문자열을 보여준다.
summaryOn : 체크되어 있을 때 보여줄 설명 문자열. 설정되어 있지 않으면 summary 문자열을 보여준다.
<PreferenceCategory android:title="입력요소">
<CheckBoxPreference
android:defaultValue="true"
android:key="data2"
android:title="체크박스"
app:icon="@drawable/arrow_back_24px"
app:summary="체크박스 요소입니다."
app:summaryOff="체크되어 있지 않습니다."
app:summaryOn="체크되어 있습니다." />
</PreferenceCategory>




defaultValue : 초기값
key : 데이터를 가져올 때 사용하는 이름
title : 화면에 보여지는 이름
summary : 표시되는 설명
icon : 좌측에 표시되는 아이콘
summary : 표시하고자 하는 설명
summaryOff : off 상태일 때 보여줄 설명 문자열. 설정되어 있지 않으면 summary 문자열을 보여준다.
summaryOn : on 상태일 때 보여줄 설명 문자열. 설정되어 있지 않으면 summary 문자열을 보여준다.
<PreferenceCategory android:title="입력요소">
<SwitchPreference
android:defaultValue="true"
android:key="data3"
android:title="스위치"
app:icon="@drawable/calendar_month_24px"
app:summary="스위치 요소입니다."
app:summaryOff="Off 상태입니다."
app:summaryOn="On 상태입니다." />
</PreferenceCategory>




항목들을 보여주고 그 중에 하나를 선택할 수 있게 한다.
defaultValue : 초기값(String)
key : 데이터를 가져올 때 사용하는 이름
title : 화면에 보여지는 이름
summary : 표시되는 설명
icon : 좌측에 표시되는 아이콘
dialogIcon : 다이얼로그의 아이콘
entries : 화면상에 보여줄 항목의 문자열
entryValues : 코드에서 사용하는 값
// strings.xml
<resources>
<string name="app_name">Android41_PreferencesScreeen</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string-array name="title_list">
<item>항목1</item>
<item>항목2</item>
<item>항목3</item>
</string-array>
<string-array name="value_list">
<item>value1</item>
<item>value2</item>
<item>value3</item>
</string-array>
</resources>
// pref.xml
<PreferenceCategory android:title="리스트 요소">
<ListPreference
android:defaultValue="value1"
android:title="단일 리스트 요소"
app:dialogIcon="@drawable/compost_24px"
app:entries="@array/title_list"
app:entryValues="@array/value_list"
app:icon="@drawable/delete_24px"
app:key="data4"
app:summary="단일 리스트 요소 입니다." />
</PreferenceCategory>

entries와 entryValues 옆에 얇은 아이콘을 누르면 리소스를 선택하는 창이 뜬다.
values폴더의 strings.xml에서 정의한 리스트를 선택하면 된다.



항목들을 보여주고 다수를 선택할 수 있다.
defaultValue : 초기값, 반드시 entryValues에 설정되어 있는 문자열 중에 원하는 것들을 모두 설정해준다.
key : 데이터를 가져올 때 사용하는 이름
title : 화면에 보여지는 이름
summary : 표시되는 설명
icon : 좌측에 표시되는 아이콘
dialogIcon : 다이얼로그의 아이콘
entries : 화면상에 보여줄 항목의 문자열
entryValues : 코드에서 사용하는 값
Component Tree에 드래그하지말고 화면에 직접 드래그 하면 아래와 같이 value를 설정해주는 창이 자동으로 뜬다.



// strings.xml
<resources>
<string name="app_name">Android41_PreferencesScreeen</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string-array name="title_list">
<item>항목1</item>
<item>항목2</item>
<item>항목3</item>
</string-array>
<string-array name="value_list">
<item>value1</item>
<item>value2</item>
<item>value3</item>
</string-array>
<string-array name="default_list">
<item>value1</item>
<item>value3</item>
</string-array>
</resources>
<MultiSelectListPreference
android:defaultValue="@array/default_list"
android:entries="@array/title_list"
android:entryValues="@array/value_list"
android:key="data5"
android:title="다중 리스트 요소"
app:dialogIcon="@drawable/done_24px"
app:icon="@drawable/format_list_bulleted_24px"
app:summary="다중 리스트 요소입니다" />



xml에서 설정한 key값으로 저장한 데이터를 가져올 수 있다.
// build.gradle 에 androidx.preference:perference 라이브러리를 추가한다.
class ResultFragment : Fragment() {
lateinit var fragmentResultBinding: FragmentResultBinding
lateinit var mainActivity: MainActivity
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentResultBinding = FragmentResultBinding.inflate(inflater)
mainActivity = activity as MainActivity
fragmentResultBinding.apply {
// PreferenceScreen을 관리하는 Preferencec 객체를 가져온다.
val pref = PreferenceManager.getDefaultSharedPreferences(mainActivity)
// 저장된 데이터를 가져온다.
// EditTextPreference
val data1 = pref.getString("data1",null)
// CheckBoxPreference
val data2 = pref.getBoolean("data2", false)
// SwitchPreference
val data3 = pref.getBoolean("data3", false)
// ListPreference
val data4 = pref.getString("data4", null)
// MultiSelectListPreference
val data5 = pref.getStringSet("data5", null)
textViewResult.apply {
text = "data1 : ${data1}\n"
append("data2 : ${data2}\n")
append("data3 : ${data3}\n")
append("data4 : ${data4}\n")
data5?.forEach {
append("data5 : ${it}\n")
}
}
}
return fragmentResultBinding.root
}
}

<resources>
<string name="app_name">Android42_BasicResource</string>
<string name="str1">안녕하세요</string>
<string name="str2">반갑습니다.</string>
</resources>
// res/values 폴더
// 프로그램에서 사용되는 값들을 설정하는 파일이 들어있다.
// values 폴더는 파일 이름은 중요하지 않다. values 폴더내에 있는 xml 파일에
// 등록되어 있는 값들의 이름으로 resource id가 만들어진다.
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
activityMainBinding.apply {
button.setOnClickListener {
// res/values/strings.xml에 등록한 문자열을 가져온다.
val str1 = resources.getString(R.string.str1)
textView.text = "${str1}\n"
// 문자열은 프로그램에서 굉장히 많이 사용하는 요소이기 때문에
// Activity에서 등록된 문자열 리소스를 가져오는 메서드를 제공한다.
val str2 = getString(R.string.str2)
textView.append("${str2}\n")
// 문자열을 설정할 수 있는 View들은 문자열 리소스 아이디를 지정할 수 있도록 제공된다.
textView.setText(R.string.str1)
}
}
}
}

<resources>
<string name="app_name">Android42_BasicResource</string>
<!-- 문자열 : %s, 정수 : %d, 실수 : %f, 그 외 : %s -->
<!-- 아~~~ 주 옛날 버전의 안드로이드 스튜디오 에서는 formatted=false 를 넣어줘야 한다. -->
<string name="str3">이름은 %s 이고, 나이는 %d 살입니다</string>
</resources>
button2.setOnClickListener {
// res/values/string.xml에 등록한 문자열을 가져온다.
// str3은 %s, %d, %f 등의 출력 양식을 가지고 있는 문자열이다.
// 각 포멧 문자에 바인딩 될 값을 지정해줘야 한다.
val str1 = getString(R.string.str3)
// % 부분에 바인딩될 값을 지정하여 문자열을 완성한다.
val str2 = String.format(str1, "홍길동", 30)
textView.text = str2
}

포멧을 %s로 지정해주면 바인딩될 값이 숫자형이어도 문자열로 변환되어 출력되며 에러는 발생하지 않는다.
반대로 %d, %f등 숫자 포멧으로 설정한 경우 문자열 값을 넣는다면 에러가 발생한다.
대부분의 경우에는 %s로 지정해주면 전부 문자열로 변환되기 때문에 %s 사용하는게 편함
아주 옛날 버전의 안드로이드 스튜디오에서는 formatted="false"를 넣어줬어야 했음
<string name="str3" formatted="false">이름은 %s 이고, 나이는 %d 살입니다</string>
<resources>
<string name="app_name">Android42_BasicResource</string>
<!-- 문자열 배열 -->
<string-array name="str4_array">
<item>항목1</item>
<item>항목2</item>
<item>항목3</item>
<item>항목4</item>
<item>항목5</item>
</string-array>
</resources>
button3.setOnClickListener {
// res/values/string.xml에 등록한 문자열 배열을 가져온다.
val str4Array = resources.getStringArray(R.array.str4_array)
textView.text = ""
str4Array.forEach {
textView.append("${it}\n")
}
}

button4.setOnClickListener {
textView.text = "색상값 테스트"
// 사전 정의되어 있는 색상값 사용
textView.setTextColor(Color.RED)
// RGB 지정 (R - Red, G - Green, B - Blue, 빛의 삼원색)
val c1 = Color.rgb(227, 30, 89)
textView.setTextColor(c1)
// ARGB 지정 (A - alpha, R, G, B)
val c2 = Color.argb(50, 227, 30, 89)
textView.setTextColor(c2)
}



// colors.xml
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<!-- RGB(0~F) -->
<color name="color1">#F00</color>
<!-- ARGB -->
<color name="color2">#5F00</color>
<!-- RRGGBB -->
<color name="color3">#00FF00</color>
<!-- AARRGGBB -->
<color name="color4">#800F55BF</color>
</resources>
button4.setOnClickListener {
textView.text = "색상값 테스트"
// 리소스에 등록된 색상
val c3 = getColor(R.color.color3)
textView.setTextColor(c3)
// 안드로이드에서 제공하는 색상들
val c4 = getColor(android.R.color.system_on_secondary_dark)
textView.setTextColor(c4)
}


코드상에서는 모두 픽셀로 작업 후 환산하는 작업이 필요
// dimen.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="px">1px</dimen>
<dimen name="dp">1dp</dimen>
<dimen name="sp">1sp</dimen>
<dimen name="mm">1mm</dimen>
<dimen name="inch">1inch</dimen>
<dimen name="pt">1pt</dimen>
</resources>
button5.setOnClickListener {
// res/values/dimen.xml에 정의한 크기 값
// 단위
// px : 픽셀의 개수. 실제로 사용하는 단위
// dp : 160ppi 액정에서 1dp = 1px. 단말기의 ppi 수치에 따른 px 값을 계산해준다.
// sp : 160ppi 액정에서 1sp = 1px. 단말기 설정에서 설정한 글자 크기에 반영된다.
// pt : 1/72 인치. 인쇄물에 사용하는 단위.
val px = resources.getDimension(R.dimen.px)
val dp = resources.getDimension(R.dimen.dp)
val sp = resources.getDimension(R.dimen.sp)
val inch = resources.getDimension(R.dimen.inch)
val mm = resources.getDimension(R.dimen.mm)
val pt = resources.getDimension(R.dimen.pt)
textView.text = "1px = ${px}px\n"
textView.append("1dp = ${dp}px\n")
textView.append("1sp = ${sp}px\n")
textView.append("1inch = ${inch}px\n")
textView.append("1mm = ${mm}px\n")
textView.append("1pt = ${pt}px\n")
}



※ 출처 : 멋쟁이사자 앱스쿨 2기, 소프트캠퍼스