[Android] ν™”λ©΄ νšŒμ „ μ‹œ 데이터 μœ μ§€

πŸ’‘ μš°μ•„ν•œν…Œν¬μ½”μŠ€μ—μ„œ ν™”λ©΄ νšŒμ§„ μ‹œ 데이터 μœ μ§€ν•˜λŠ” 방법에 λŒ€ν•΄ ν•™μŠ΅ν•œ λ‚΄μš©μ„ κΈ°λ‘ν•˜μ˜€μŠ΅λ‹ˆλ‹€ !

 

κ°œμš”

  • λ””λ°”μ΄μŠ€ 화면을 νšŒμ „ν•˜λ©΄ λ™μ μœΌλ‘œ μƒμ„±ν•œ 데이터가 μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.
  • μ΄λŠ” λŒ€ν‘œμ μΈ μ•‘ν‹°λΉ„ν‹°κ°€ μ’…λ£Œλ˜λŠ” 상황듀 쀑 3λ²ˆμ§Έμ— ν•΄λ‹Ήν•©λ‹ˆλ‹€.
    1. λ’€λ‘œκ°€κΈ°λ‘œ μ’…λ£Œ
    2. finish() λ©”μ„œλ“œ 호좜
    3. μ‹œμŠ€ν…œμ— μ˜ν•œ μ’…λ£Œ
  • 3번째 κ²½μš°λŠ” ν™ˆ ν‚€λ₯Ό 눌러 화면에 보이지 μ•Šμ€ μƒνƒœλ‘œ μž₯μ‹œκ°„ κ²½κ³Όν•  λ•Œ, 화면을 νšŒμ „ν•  λ•Œ λ°œμƒν•©λ‹ˆλ‹€.

  • 이 λ•Œ μ•‘ν‹°λΉ„ν‹° 생λͺ…주기에 λ”°λΌμ„œ onDestory()κ°€ 호좜되며 μ’…λ£Œλ˜κ³ , μƒˆλ‘œ μƒμ„±λ˜λ©΄μ„œ onCreate()λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€.
  • 이 λ•Œ 기쑴에 μœ μ§€ν•˜κ³  있던 UI μƒνƒœμ™€ 동적 데이터가 μ΄ˆκΈ°ν™” λ˜λŠ” λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€.
  • 이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ onSaveInstanceState()와 onRestoreInstanceState()λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μƒνƒœ μ €μž₯ 및 볡원

onSaveInstanceState()

  • λ©”μ„œλ“œλŠ” Activityκ°€ 파괴되기 전에 호좜되며 Bundle 객체에 μƒνƒœ 정보λ₯Ό μ €μž₯ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν•΄λ‹Ή 정보λ₯Ό onCreate()와 onRestoreInstanceState()둜 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.

onRestoreInstanceState()

  • μ €μž₯된 μƒνƒœλ₯Ό savedInstanceState(Bundle)둜 λ°›μ•„μ„œ μ €μž₯된 μƒνƒœλ₯Ό λ³΅μ›ν•©λ‹ˆλ‹€.
  • onStart() 이후에 호좜되며, μ΄μ „에 μ €μž₯된 μƒνƒœ 데이터λ₯Ό 볡원할 λ•Œλ§Œ μ‹€ν–‰λ©λ‹ˆλ‹€.
  • 즉 Activityκ°€ 처음 μƒμ„±λœ μ‹œμ μ—μ„œλŠ” ν˜ΈμΆœν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

onCreate()μ—μ„œλ„?

  • onCreate()μ—μ„œλ„ savedInstanceStateλ₯Ό λ°›μ•„μ„œ μƒνƒœλ₯Ό 볡원할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν•˜μ§€λ§Œ 이 κ²½μš°λŠ” null인 경우λ₯Ό ν¬ν•¨ν•˜λ©°, Activityκ°€ 처음 μ‹œμž‘λœ 경우λ₯Ό ν¬ν•¨ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.
  • λ°˜λ©΄μ— onRestoreInstanceState()λŠ” 볡원 된 μƒνƒœμΌ λ•Œλ§Œ ν˜ΈμΆœλ©λ‹ˆλ‹€.
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // μƒνƒœ 볡원
        if (savedInstanceState != null) {
            val savedText = savedInstanceState.getString("saved_text")
            // λ³΅μ›λœ μƒνƒœλ₯Ό UI에 반영
            findViewById<TextView>(R.id.textView).text = savedText
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        // μƒνƒœ μ €μž₯
        val textToSave = findViewById<TextView>(R.id.textView).text.toString()
        outState.putString("saved_text", textToSave)
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        super.onRestoreInstanceState(savedInstanceState)
        // μƒνƒœ 볡원
        val savedText = savedInstanceState.getString("saved_text")
        findViewById<TextView>(R.id.textView).text = savedText
    }
}

ViewModel ν™œμš©

  • ViewModel은 ν™”λ©΄ νšŒμ „κ³Ό 같은 ꡬ성 λ³€κ²½ μ‹œμ—λ„ 데이터가 μœ μ§€λ˜λ„λ‘ λ„μ™€μ£ΌλŠ” Android Architecture Componentμž…λ‹ˆλ‹€.
  • ViewModel은 μ•‘ν‹°λΉ„ν‹°λ‚˜ ν”„λž˜κ·Έλ¨ΌνŠΈκ°€ μž¬μƒμ„±λ  λ•Œλ„ 데이터가 μœ μ§€λ˜λ©°, UI κ΄€λ ¨ 데이터λ₯Ό μ €μž₯ν•˜λŠ” 데 μ ν•©ν•©λ‹ˆλ‹€.

ν™”λ©΄ νšŒμ „ 처리 방법 μ œμ–΄

  • μ•„μ˜ˆ 회면 νšŒμ „ μ‹œ μƒνƒœλ₯Ό 무쑰건 μœ μ§€ν•˜λŠ” 방법이 μžˆμŠ΅λ‹ˆλ‹€.
  • 쑰금 극단적일 μˆ˜λ„ μžˆμ§€λ§Œ, ꡳ이 ν™”λ©΄ νšŒμ „μ΄ ν•„μš”μ—†λŠ” μ•±μ—μ„œ ν™”λ©΄ νšŒμ „μ„ μ œμ–΄ν•˜μ—¬ λΆˆν•„μš”ν•œ λ‘œμ§μ„ μ œκ±°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

configChanges

  • AndroidManifest.xmlμ—μ„œ configChanges 속성을 μ„€μ •ν•˜λ©΄ ν™”λ©΄ νšŒμ „ μ‹œ μ•‘ν‹°λΉ„ν‹°κ°€ μž¬μƒμ„±λ˜μ§€ μ•Šλ„λ‘ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize">
</activity>

μœ„ν—˜μ„±

  • 이 속성은 일반적으둜 ꢌμž₯λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • ν™”λ©΄ νšŒμ „ μ‹œ μžλ™μœΌλ‘œ Activityλ₯Ό μž¬μƒμ„±ν•˜μ—¬ 화면을 μ΅œμ ν™”ν•˜λŠ” Android의 κΈ°λ³Έ λ™μž‘μ„ μš°νšŒν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

Fragmentμ—μ„œ λŒ€μ‘ν•˜κΈ°

  • Fragmentμ—μ„œλ„ Activity와 μœ μ‚¬ν•˜κ²Œ onSaveInstanceState() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μƒνƒœλ₯Ό μ €μž₯ν•˜κ³  볡원할 수 μžˆμŠ΅λ‹ˆλ‹€.
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // 이전 μƒνƒœκ°€ 있으면 볡원
    savedInstanceState?.let {
        val savedText = it.getString("saved_text")
        findViewById<TextView>(R.id.textView).text = savedText
    }
}

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    // μƒνƒœ μ €μž₯
    outState.putString("saved_text", "Hello, World!")
}

override fun onViewStateRestored(savedInstanceState: Bundle?) {
    super.onViewStateRestored(savedInstanceState)

    // μƒνƒœ 볡원
    savedInstanceState?.let {
        val savedText = it.getString("saved_text")
        view?.findViewById<TextView>(R.id.textView)?.text = savedText
    }
}
  • Fragment도 Activity와 λ§ˆμ°¬κ°€μ§€λ‘œ μƒˆλ‘œ μƒμ„±λœ μƒνƒœλΌλ©΄ onCreate(), μƒνƒœλ₯Ό 볡원할 λ•ŒλŠ” onViewStateRestored()λ₯Ό ν™œμš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Fragment μž¬μƒμ„± 방지

  • Fragmentμ—μ„œ retainInstance μ˜΅μ…˜μ„ ν†΅ν•΄μ„œ Fragmentκ°€ Activityκ°€ μž¬μƒμ„± λ˜μ–΄λ„ νŒŒκ΄΄λ˜μ§€ μ•Šλ„λ‘ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
class MyFragment : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        retainInstance = true // ν™”λ©΄ νšŒμ „ μ‹œ Fragment μœ μ§€
    }
}

정리

  • Androidμ—μ„œ ν™”λ©΄ νšŒμ „ μ‹œ μ•‘ν‹°λΉ„ν‹° μƒνƒœ μœ μ§€λ₯Ό μœ„ν•΄ onSaveInstanceState()λ₯Ό ν™œμš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • νŠΉλ³„ν•œ 경우λ₯Ό μ œμ™Έν•˜κ³  configChangesλ₯Ό μ‚¬μš©ν•˜λŠ” 것을 μ§€μ–‘ν•˜κ³ , Androidκ°€ μ œκ³΅ν•˜λŠ” κΈ°λ³Έ λ™μž‘μ„ ν™œμš©ν•˜μ—¬ μƒνƒœλ₯Ό κ΄€λ¦¬ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.