본문 바로가기
Native App/👽Android

#02 SharedPreferences

by yewoneeee 2022. 6. 16.

https://developer.android.com/training/data-storage/shared-preferences?hl=ko 

 

키-값 데이터 저장  |  Android 개발자  |  Android Developers

키-값 데이터 저장 저장하려는 키-값 컬렉션이 비교적 작은 경우 SharedPreferences API를 사용해야 합니다. SharedPreferences 객체는 키-값 쌍이 포함된 파일을 가리키며 키-값 쌍을 읽고 쓸 수 있는 간단

developer.android.com

https://www.youtube.com/watch?v=4rYMfpbpwPA&list=PL_XkuR-7VWcuee4kxHgChRvQCmHxcJnfS&index=13 

위 영상 참고해서 실습했음


데이터를 앱에 저장하는 방법

  1. 파일 I/O (내부 또는 외부 저장소)
    접근 권한을 획득하고 파일을 열었다 닫았다 하는 수고가 필요
  2. 관계형 데이터베이스
    간단한 데이터를 저장할 것이라면 구축과 관리에 많은 시간과 노력이 요구됨
    SQLite 등을 이용해 복잡한 관계형 데이터를 저장할 수 있음

  3. SharedPreference
    내부적으로는 XML 파일로 저장됨
    파일을 열고 닫을 필요 없이 핸들러만 만들어서 간편하게 사용 가능
    Key = Value 형태로 저장 가능

SharedPreferences 사용법

 

1) sharedPreferences 객체 생성

  1. getPreferenes : 하나의 Activity에서만 사용 가능, 특정 Activity만의 설정값을 저장할 때 사용
  2. getSharedPreferences : 앱의 모든 context에서 호출 가능, 주로 앱의 전역 데이터값을 저장할 때 사용
  3. getDefaultSharedPreferences
val sharedPreferences = getSharedPreferences(key, mode)

 

getSharedPreferences(key, mode) : 핸들러를 받아옴

mode 종류
- MODE_PRIVATE
- MODE_WORLD_READABLE (deprecated)
- MODE_WORLD_WRITEABLE (deprecate)
- MODE_MULTI_PROCESS

작성한 앱에서만 접근 가능하게 하는 MODE_PRIVATE 사용
WORLD가 붙은 모드는 다른 앱에서도 사용이 가능하게 할 수 있다고 알아두기

 

2) editor 생성

    edit() 메소드 사용

val editor = sharedPreferences.edit()

    editor를 써서 기록할 데이터를 메모리에 올림

 

3) 데이터 쓰기 (메모리 상의 값에 대한 쓰기 작업)

editor.putInt(key, value)
editor.putBoolean(key, value)

 

4) 실제 파일에 쓰기 작업

  1. apply() : 호출 후 곧바로 리턴되어 스레드를 블록시키지 않음
  2. commit() : 호출 시 스레드 블록되어 커널에서 파일 저장 완료 후 함수는 리턴되고
                     스레드는 다시 작동하며 처리 결과를 true/ false로 반환

   결과값이 필요없다면 apply를 사용하는 것이 반응성 면에서 좋음

editor.apply()

 

▽ 출처

 


실습

 

1) activity_main.xml

 

xml 화면

▽ 코드

더보기
<!-- XML -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/game_setting_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Game Settings"
        android:textSize="30dp"
        android:layout_marginStart="20dp"
        android:layout_marginTop="40dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/graphic_quality_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Graphic Quality"
        android:layout_marginTop="30dp"
        app:layout_constraintStart_toStartOf="@id/game_setting_tv"
        app:layout_constraintTop_toBottomOf="@+id/game_setting_tv"/>

    <RadioGroup
        android:id="@+id/graphic_quality_rg"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:checkedButton="@id/graphic_quality_Medium_rb"
        app:layout_constraintTop_toBottomOf="@id/graphic_quality_tv"
        app:layout_constraintStart_toStartOf="@id/graphic_quality_tv">
        <RadioButton
            android:id="@+id/graphic_quality_low_rb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="10dp"
            android:text="Low"/>
        <RadioButton
            android:id="@+id/graphic_quality_Medium_rb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="10dp"
            android:text="Medium"/>
        <RadioButton
            android:id="@+id/graphic_quality_high_rb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="10dp"
            android:text="High"/>
    </RadioGroup>

    <TextView
        android:id="@+id/music_volume_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Music Volume"
        android:layout_marginTop="30dp"
        app:layout_constraintStart_toStartOf="@id/game_setting_tv"
        app:layout_constraintTop_toBottomOf="@+id/graphic_quality_rg"/>

    <SeekBar
        android:id="@+id/music_volume_sb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="50"
        android:layout_marginStart="30dp"
        android:layout_marginEnd="30dp"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@id/music_volume_tv"/>


    <TextView
        android:id="@+id/sfx_volume_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SFX Volume"
        android:layout_marginTop="30dp"
        app:layout_constraintStart_toStartOf="@id/game_setting_tv"
        app:layout_constraintTop_toBottomOf="@+id/music_volume_sb"/>

    <SeekBar
        android:id="@+id/sfx_volume_sb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="50"
        android:layout_marginStart="30dp"
        android:layout_marginEnd="30dp"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@id/sfx_volume_tv"/>

    <TextView
        android:id="@+id/enable_vertical_sync_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Enable Vertical Sync"
        android:layout_marginTop="30dp"
        app:layout_constraintStart_toStartOf="@id/game_setting_tv"
        app:layout_constraintTop_toBottomOf="@+id/sfx_volume_sb"/>

    <Switch
        android:id="@+id/vsync_switch"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="20dp"
        android:checked="true"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@id/enable_vertical_sync_tv"
        app:layout_constraintBottom_toBottomOf="@id/enable_vertical_sync_tv"/>

    <Button
        android:id="@+id/save_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Save"
        android:layout_marginTop="30dp"
        app:layout_constraintTop_toBottomOf="@id/enable_vertical_sync_tv"
        app:layout_constraintEnd_toStartOf="@id/load_btn"
        app:layout_constraintStart_toStartOf="parent"/>

    <Button
        android:id="@+id/load_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Load"
        android:layout_marginTop="30dp"
        app:layout_constraintTop_toBottomOf="@id/enable_vertical_sync_tv"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/save_btn"/>


</androidx.constraintlayout.widget.ConstraintLayout>

 

2) MainActivity.kt

package com.example.sharedpreferencetest

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.widget.Toast
import com.example.sharedpreferencetest.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.saveBtn.setOnClickListener {
            savePref()
        }
        binding.loadBtn.setOnClickListener {
            loadPref()
        }
    }
    private fun savePref(){ // save 버튼 터치시 동작
        val sharedPreferences = getSharedPreferences(KEY_PREFS, MODE_PRIVATE) // sharedPreferences 객체 생성
        val editor = sharedPreferences.edit() // editor 생성
		
        // 메모리 상에 데이터 쓰기
        editor.putInt(KEY_GRAPHIC, binding.graphicQualityRg.checkedRadioButtonId)
        editor.putInt(KEY_MUSIC,binding.musicVolumeSb.progress)
        editor.putInt(KEY_SFX,binding.sfxVolumeSb.progress)
        editor.putBoolean(KEY_VSYNC,binding.vsyncSwitch.isChecked)

		// 실제 파일에 쓰기 작업
        editor.apply()
        // 확인용 토스트 메시지
        Toast.makeText(this,"Game settings has saved",Toast.LENGTH_SHORT).show()
    }

    private fun loadPref(){ // load 버튼 터치시 동작
        val sharedPreferences = getSharedPreferences(KEY_PREFS, Context.MODE_PRIVATE) // sharedPreferences 핸들러 받아옴
        if(sharedPreferences.contains(KEY_GRAPHIC)){ // 저장된 값이 있다면 값 가져오기
            val graphicValue = sharedPreferences.getInt(KEY_GRAPHIC,0)
            val musicValue = sharedPreferences.getInt(KEY_MUSIC,50)
            val sfxValue = sharedPreferences.getInt(KEY_SFX,50)
            val vsyncValue = sharedPreferences.getBoolean(KEY_VSYNC,true)

			// 저장해놓은 값으로 UI 변경
            binding.graphicQualityRg.check(graphicValue)
            binding.musicVolumeSb.progress = musicValue
            binding.sfxVolumeSb.progress = sfxValue
            binding.vsyncSwitch.isChecked = vsyncValue

			// 확인용 토스트 메시지 출력
            Toast.makeText(this,"Game setting has loaded",Toast.LENGTH_SHORT).show()
        }
    }

    // SharedPreference는 key = value값으로 저장하기 때문에 
	// savePref와 loadPref에서 동시에 사용하는 key값을 companion object로 미리 설정
    companion object{ // static 정도로 생각
        private const val KEY_PREFS = "game_settings"
        private const val KEY_GRAPHIC = "graphic_quality"
        private const val KEY_MUSIC = "music_volume"
        private const val KEY_SFX = "sfx_volume"
        private const val KEY_VSYNC = "vertical"
    }
}

결과 화면

1) 시작 화면

기본 설정 값으로 화면 출력됨

2) 세팅 변경 후 save

변경된 세팅 저장 후 토스트 메시지 출력

3) 앱을 나갔다가 load

load 버튼 누르면 저장해둔 세팅 값으로 변경

 

 

간단한 값들을 저장할 때 유용하게 사용됨

jwt 저장 등

'Native App > 👽Android' 카테고리의 다른 글

web Crawling - Jsoup  (0) 2022.06.27
kakao login api 사용 - 2  (0) 2022.06.19
kakao login api 사용 - 1  (0) 2022.06.16
#01 Coroutine  (0) 2022.06.04
우분투 환경에 안드로이드 스튜디오 설치  (0) 2022.01.24

댓글