본문 바로가기

TLI/Android

Shared Preference / Room

SharedPreference

  • 앱에 영구적으로 데이터를 저장하는 파일
  • xml파일에 key:value 형식의 String타입으로 저장된다.
  • 주로 설정과 관련된 데이터를 저장한다.
    • 알림 / 앱의 기본 설정사항 등

사용 방법

저장

  1. getSharedPreferences("저장할 xml파일명", mode: Int)
  2. edit() : 편집 모드로 전환
  3. edit.putString(key, value)로 저장
  4. apply() : 저장 완료(commit)
private fun saveData(){
    val pref = getSharedPreferences("pref", 0)
    val edit = pref.edit()

    edit.putString("name", binding.etMain.text.toString())
    edit.apply()
}

device의 `/data/data/프로젝트명/shared_prefs` 에 지정한 xml파일 명(예시의 pref.xml)에 저장되어 있다.

pref.xml

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="name">android!!</string>
</map>

조회

  1. getSharedPreferences("조회할 xml파일명", mode: Int)
  2. getString(key, value)
private fun loadData() {
    val pref = getSharedPreferences("pref", 0)
    binding.etMain.setText(pref.getString("name", ""))
}

Room

  • in-app DB
  • SqLite대신 사용을 권장한다.
  • JPA와 문법이 거의 동일하다.

사용 방법

  1. Database(abstact class) 생성
  • migration을 원하면 static으로 Migration객체를 만들어 놓으면 된다.
    • 예제에서는 사용하지 않았다.
@Database(entities = [Student::class], exportSchema = false, version = 1)
abstract class MyDatabase : RoomDatabase() {

    abstract fun getMyDao() : MyDao

    companion object {
        private var INSTANCE: MyDatabase? = null
        private val MIGRATION_1_2 = object : Migration(1,2) {
            override fun migrate(database: SupportSQLiteDatabase) {

            }
        }

        fun getDatabase(context: Context): MyDatabase {
            if(INSTANCE == null) {
                INSTANCE = Room.databaseBuilder(
                    context, MyDatabase::class.java, "scholl_database")
                    .addMigrations(MIGRATION_1_2)
                    .build()
            }
            return INSTANCE as MyDatabase
        }
    }
}
  1. Entity(data class)생성
@Entity
data class Student(
    @PrimaryKey
    val id: Int,
    val name: String
)
  1. Dao interface 생성
  • LiveData를 사용하지 않는다면 suspend를 추가해서 thread-safe하게 만들어줘야 한다.
@Dao
interface MyDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE) // id가 겹칠 경우 새로운 값으로 대체
    suspend fun insertStudent(student: Student)

    @Query("SELECT * FROM student")
    fun getAllStudents(): LiveData<List<Student>>

    @Query("SELECT * FROM student WHERE name = :sname")
    suspend fun getStudentsByName(sname: String): List<Student>

    @Delete
    suspend fun deleteStudent(student: Student)

}
  1. Activity에서 dao 의존성 주입해서 사용
  • LiveData인 경우에는 thread-safe하기 따로 비동기 처리를 하지 않아도 된다.
  • 변화가 있을 때(추가) 실시간으로 observe해서 text에 추가한다.
val allStudents = myDao.getAllStudents()
allStudents.observe(this){
    val str = StringBuilder().apply{
        for ((id, name) in it) {
            append(id)
            append("-")
            append(name)
            append("\n")
        }
    }.toString()
    binding.textStudentList.text = str
}
  • 아닌 경우에는 CouroutineScope로 감싸서 사용해야 한다.
binding.addStudent.setOnClickListener {
    val id = binding.editStudentId.text.toString().toInt()
    val name = binding.editStudentName.text.toString()
    if(id > 0 && name.isNotEmpty()) {
        CoroutineScope(Dispatchers.IO).launch {
            myDao.insertStudent(Student(id, name))
        }
    }
    binding.editStudentId.text = null
    binding.editStudentName.text = null
}

'TLI > Android' 카테고리의 다른 글

OnBackPressedCallback(true)  (0) 2024.08.25
ListAdapter의 holder 재사용  (0) 2024.08.24
Retrofit  (0) 2024.08.09
Compose(Recomposition/rememeber/state hoisting)  (0) 2024.08.04
2024.07.30 TIL(RecyclerView)  (0) 2024.07.30