ウィンドウサイズの変更に強い堅牢な画面の構築 / DroidKaigi 2018

C4221ba79492601eb59a9ef5d4f4bbaa?s=47 nakamuuu
February 09, 2018

ウィンドウサイズの変更に強い堅牢な画面の構築 / DroidKaigi 2018

DroidKaigi 2018 での発表資料です。 https://droidkaigi.jp/2018/
Room 3 - 2018/02/09 16:50-17:20

【参考資料 / リンク】
>
・android:fitsSystemWindows - View | Android Developers
https://developer.android.com/reference/android/view/View.html#attr_android:fitsSystemWindows
・OnApplyWindowInsetsListener (v4 compat library) | Android Developers
https://developer.android.com/reference/android/support/v4/view/OnApplyWindowInsetsListener.html
・View#dispatchApplyWindowInsets | Android Developers
https://developer.android.com/reference/android/view/View.html#dispatchApplyWindowInsets(android.view.WindowInsets)
・ViewGroup#dispatchApplyWindowInsets | Android Developers
https://developer.android.com/reference/android/view/ViewGroup.html#dispatchApplyWindowInsets(android.view.WindowInsets)
・View#onApplyWindowInsets | Android Developers
https://developer.android.com/reference/android/view/View.html#onApplyWindowInsets(android.view.WindowInsets)

>
・Handling Configuration Changes | Android Developers
https://developer.android.com/guide/topics/resources/runtime-changes.html
・guardian/toolargetool | GitHub
https://github.com/guardian/toolargetool
・frankiesardo/Icepick | GitHub
https://github.com/frankiesardo/icepick
・nakamuuu/Retainer | GitHub
https://github.com/nakamuuu/retainer
・StateAwareViewModel - nakamuuu | GitHug Gist
https://gist.github.com/nakamuuu/29d7e358735ab867fb145c210d49f8af
・Of Bundles and ViewModels | ProAndroidDev
https://proandroiddev.com/customizing-the-new-viewmodel-cf28b8a7c5fc

C4221ba79492601eb59a9ef5d4f4bbaa?s=128

nakamuuu

February 09, 2018
Tweet

Transcript

  1. ΢Οϯυ΢αΠζͷมߋʹڧ͍ ݎ࿚ͳը໘ͷߏங

  2. Fablic, inc. Android Application Developer தଜܙଠ @nakamuuu @chicken_111 2 ࣗݾ঺հ

  3. ྦྷܭ ສ μ΢ϯϩʔυ ಥഁʂ 3 ϑϦϚΞϓϦʮϑϦϧʯʹ͍ͭͯ

  4. ϑϦϚΞϓϦʮϑϦϧʯʹ͍ͭͯ 4 ϑϦϚΞϓϦʮϑϦϧʯ͸ ৽͍͠ʮϥΫϚʯͱͯ͠ੜ·ΕมΘΓ·͢ʂ ʢ50%0-1ͷεΫγϣʣ

  5. ྦྷܭ 5 ϑϦϚΞϓϦʮϑϦϧʯʹ͍ͭͯ

  6. ʰ΢Οϯυ΢αΠζͷมߋʹڧ͍ ɹݎ࿚ͳը໘ʱͱ͸ʁ 6

  7. 7 ΢Οϯυ΢αΠζͷมߋ ը໘ճస Ϛϧν΢Οϯυ΢ ʰ΢Οϯυ΢αΠζͷมߋʹڧ͍ݎ࿚ͳը໘ʱͱ͸ʁ

  8. 8 ʰ΢Οϯυ΢αΠζͷมߋʹڧ͍ݎ࿚ͳը໘ʱͱ͸ʁ ΢Οϯυ΢αΠζͷมߋΛߟྀ͠ͳ͍ͱʜʁ

  9. 9 ϨΠΞ΢τͷ่Ε ʢྫʣ௨ৗͱҟͳΔγεςϜ6*ͷ഑ஔΛߟྀͰ͖͍ͯͳ͍ ʰ΢Οϯυ΢αΠζͷมߋʹڧ͍ݎ࿚ͳը໘ʱͱ͸ʁ εςʔλεόʔ෼ͷ༨ന

  10. 10 ը໘ͷঢ়ଶ͕ࣦΘΕΔ ʰ΢Οϯυ΢αΠζͷมߋʹڧ͍ݎ࿚ͳը໘ʱͱ͸ʁ

  11. 11 ʰ΢Οϯυ΢αΠζͷมߋʹڧ͍ݎ࿚ͳը໘ʱ ɾ͍͔ͳΔ΢Οϯυ΢αΠζɾγεςϜ6*ͷ഑ஔͰ΋ ɹϨΠΞ΢τͷ่Ε͕ൃੜ͠ͳ͍ ɾߏ੒ͷมߋΛލ͍Ͱ΋"DUJWJUZ'SBHNFOU͕ ɹը໘ͷঢ়ଶΛద੾ʹอ࣋ɾදࣔ͢Δ ʰ΢Οϯυ΢αΠζͷมߋʹڧ͍ݎ࿚ͳը໘ʱͱ͸ʁ

  12. 12 w΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங w8JOEPX*OTFUTΛཧղͯ͠ɺγεςϜ6*ͷ഑ஔʹɹ Өڹ͞Εͳ͍ϨΠΞ΢τΛ૊Ή wߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ wTBWFE*OTUBODF4UBUFɺTFU3FUBJO*OTUBODFɺɹɹ ͦΕͧΕͷঢ়ଶอ࣋ͷख๏ͷར఺ͱ࢖͍෼͚ ࠓ೔͓࿩͢͠Δ͜ͱ

  13. ΢Οϯυ΢αΠζͷมߋʹڧ͍ ϨΠΞ΢τͷߏங 13

  14. 14 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங Ϛϧν΢Οϯυ΢ػೳͷଘࡏ ϨΠΞ΢τͷߏஙͰߟྀ͢΂͖͜ͱ͕૿͑ͨ w෯ɾߴ͞ڞʹදࣔྖҬ͕ڱ͍ঢ়ଶͰͷϨΠΞ΢τ wMBZPVUEJNFOϦιʔεͷΑΓద੾ͳ࢖͍෼͚ w௨ৗͱҟͳΔγεςϜ6*ʢεςʔλεόʔ౳ʣͷ഑ஔ

  15. 15 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங ௨ৗͱҟͳΔγεςϜ6*ʢεςʔλεόʔ౳ʣͷ഑ஔ εςʔλεόʔͷߴ͞Λ ద੾ʹѻΘͳ͍ͱ༨෼ͳεϖʔε͕

  16. 16 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங ෆࢥٞͳεςʔλεόʔͷ୺຤΋ʜʁ

  17. 17 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங 04όʔδϣϯ͝ͱʹఆٛʜʁ <dimen name=“status_bar_height”>0dp</dimen> WBMVFTEJNFOTYNM <dimen name=“status_bar_height”>25dp</dimen> WBMVFTWEJNFOTYNM <dimen

    name=“status_bar_height”>24dp</dimen> WBMVFTWEJNFOTYNM val resId = res.getIdentifier(“status_bar_height”, “dimen”, “android”) val statusBarHeight = res.getDimensionPixelSize(resId) γεςϜϦιʔεΛऔಘʜʁ
  18. 18 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங BOESPJEGJUT4ZTUFN8JOEPXT ʮεςʔλεόʔͷߴ͞Λऔಘ͢Δʯͱ͍͏ Ξϓϩʔν͸Ұ୴ٙ͏΂͖ #PPMFBOJOUFSOBMBUUSJCVUFUPBEKVTUWJFXMBZPVUCBTFEPO TZTUFNXJOEPXTTVDIBTUIFTUBUVTCBS*GUSVF BEKVTUTUIF QBEEJOHPGUIJTWJFXUPMFBWFTQBDFGPSUIFTZTUFNXJOEPXT

  19. 19 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங   ฐࣾ"OESPJEΤϯδχΞʹฉ͖·ͨ͠ งғؾͰ࢖͍ͬͯΔ7JFXͷϓϩύςΟ͸ʁ GJUT4ZTUFN8JOEPXT ະճ౴

  20. 20 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங   ฐࣾ"OESPJEΤϯδχΞʹฉ͖·ͨ͠ งғؾͰ࢖͍ͬͯΔ7JFXͷϓϩύςΟ͸ʁ GJUT4ZTUFN8JOEPXT ະճ౴ ʢճ౴਺ʣ

  21. 21 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங ʢσϑΥϧτͷڍಈʣ wGJUT4ZTUFN8JOEPXTΛࢦఆ͢ΔͱγεςϜ6*෼ͷ QBEEJOHΛ͚ͭͯදࣔˍࢠ7JFXΛ഑ஔ͢Δ wGJUT4ZTUFN8JOEPXTΛࢦఆͨ͠7JFX͕ෳ਺ݸɹ ଘࡏ͢Δ৔߹ɺਂ͞༏ઌతʹ୧ͬͨ࠷ॳͷ7JFX͚ͩ Πϯηοτ͕EJTQBUDI͞ΕΔ w8JOEPX*OTFUTʹDPOTVNFEͰ͋Δ͔ͷϑϥά͕ ଘࡏ͢Δ

    ˞7JFXPO"QQMZ8JOEPX*OTFUT7JFX(SPVQEJTQBUDI"QQMZ8JOEPX*OTFUTࢀর
  22. 22 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங ˞TFU4ZTUFN6J7JTJCJMJUZ 4:45&.@6*@'-"(@-":065@'6--4$3&&/ c4:45&.@6*@'-"(@-":065@45"#-& Λࢦఆ <FrameLayout android:fitsSystemWindows=“true|false”> <android.support.v7.widget.Toolbar />

    </FrameLayout>
  23. 23 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங <LinearLayout android:orientation=“horizontal”> <FrameLayout android:fitsSystemWindows=“true”> <android.support.v7.widget.Toolbar /> </FrameLayout> <FrameLayout

    android:fitsSystemWindows=“true”> <android.support.v7.widget.Toolbar /> </FrameLayout> </LinearLayout>
  24. 24 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங GJUT4ZTUFN8JOEPXTΛUSVFʹͰ͖Δ7JFX͸͚ͭͩʁ <android.support.v4.widget.DrawerLayout android:fitsSystemWindows=“true”> <android.support.constraint.ConstraintLayout /> <android.support.design.widget.NavigationView android:layout_gravity=“start” android:fitsSystemWindows=“true”

    /> </android.support.v4.widget.DrawerLayout> ʢ"OESPJE4UVEJPͷςϯϓϨʔτʮ/BWJHBUJPO%SBXFS"DUJWJUZʯʣ
  25. 25 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங ࣗ਎·ͨ͸ࢠ7JFXͷGJUT4ZTUFN8JOEPXTͷ ղऍΛΧελϚΠζ͢Δ͜ͱ͕Մೳ 8JOEPX*OTFUTΛQBEEJOHʹ෇͚ସ͑Δͷ͸ 7JFXPO"QQMZ8JOEPX*OTFUTͰͷσϑΥϧτͷڍಈ

  26. 26 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங 7JFXPO"QQMZ8JOEPX*OTFUT 8JOEPX*OTFUTΛQBEEJOHʹ෇͚ସ͑Δͷ͕σϑΥϧτ ΦʔόʔϥΠυ͠ͳͯ͘΋ 0O"QQMZ8JOEPX*OTFUT-JTUFOFSͰॲཧΛԣऔΓͰ͖Δ // View#onApplyWindowInsetsͷ୅ΘΓʹݺ͹ΕΔ ViewCompat.setOnApplyWindowInsetsListener(view) {

    v, insets -> // View#onApplyWindowInsets ͷσϑΥϧτͷॲཧΛߦ͏͜ͱ΋Մೳ val result = ViewCompat.onApplyWindowInsets(v, insets) // ద੾ͳWindowInsetsΛฦ͢ return result }
  27. ʢ%SBXFS-BZPVUͷڍಈʣ 27 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங w0O"QQMZ8JOEPX*OTFUT-JTUFOFSͰ 8JOEPX*OTFUTͷมߋΛݕ஌SFRVFTU-BZPVU  w7JFXPO"QQMZ8JOEPX*OTFUT͕ݺ͹Εͳ͘ͳΓɺ QBEEJOH͕෇༩͞Εͳ͘ͳΔ wPO.FBTVSFͰGJUT4ZTUFN8JOEPXT͕USVFͳɹɹ ࢠ7JFXʹରͯ͠ΠϯηοτΛ௚઀EJTQBUDI

    wಉ࣌ʹGJUT4ZTUFN8JOEPXT͕GBMTFͳࢠ7JFXͷ NBSHJOʹΠϯηοτ෼ͷ஋Λઃఆ
  28. 28 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங ίϯςϯπྖҬ ʢGJUT4ZTUFN8JOEPXTGBMTFʣ wPO.FBTVSFͰNBSHJOΛ෇༩͞ ΕΔͷͰεςʔλεόʔʹඃΒͣ දࣔ͞ΕΔ ˞εςʔλεόʔͷྖҬ͸0O"QQMZ8JOEPX*OTFUT-JTUFOFSͰऔಘ͞Εͨ ΠϯηοτΛجʹ%SBXFS-BZPVU͕ࣗલͰృΓͭͿ͢ ʢBOESPJETUBUVT#BS$PMPSʹ͸!BOESPJEDPMPSUSBOTQBSFOUΛࢦఆʣ

  29. 29 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங /BWJHBUJPO7JFX ʢGJUT4ZTUFN8JOEPXTUSVFʣ w8JOEPX*OTFUT͕QBEEJOHʹ ෇͚ସ͑ΒΕͳ͍ͷͰεςʔλ εόʔͷྖҬ·Ͱදࣔ͞ΕΔ w8JOEPX*OTFUT͕EJTQBUDI ͞ΕΔͷͰɺΠϯηοτΛϋϯ υϧͰ͖Δ

  30. 30 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங ࠔͬͨ࣌ͷEJTQBUDIܳ ࣗ਎ʹ΋ࢠ7JFXʹ΋8JOEPX*OTFUTΛ෇༩͍ͤͨ͞ʂ wPO.FBTVSF΍PO"QQMZ8JOEPX*OTFUTͰࢠ7JFX ͷEJTQBUDI"QQMZ8JOEPX*OTFUTΛ௚઀ݺͿ wྫ͑͹/BWJHBUJPO7JFXͰ͸ࣗ਎ʹ෇༩͞Εͨɹɹ ΠϯηοτΛϔομʔ༻ͷ7JFX΁EJTQBUDI͍ͯ͠Δ ˞/BWJHBUJPO.FOV1SFTFOUFSEJTQBUDI"QQMZ8JOEPX*OTFUTࢀর

  31. 31 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங ͋Δ͍͸ʜ PO"QQMZ8JOEPX*OTFUTͰDPOTVNF͠ͳ͍ ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets -> //

    View#onApplyWindowInsets ͷσϑΥϧτͷॲཧΛߦΘͤΔ ViewCompat.onApplyWindowInsets(v, insets) // ௨ৗ͸insets.consumeSystemWindowInsets()Λฦ͕͢ɺ // ࣗ਎Ҏ߱ͷViewʹ΋ΠϯηοτΛ෇༩͍ͨ͠ͷͰinsetsΛͦͷ··ฦ͢ return insets } GJUT4ZTUFN8JOEPXTUSVFͳΒDPOTVNF͞ΕΔ લఏ่͕ΕΔͷͰཚ༻͢Δͱࠞಱͱͦ͠͏ʜ
  32. 32 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங εςʔλεόʔͷߴ͞Λऔಘ͢Δ ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets -> statuBarSize =

    insets.systemWindowInsetTop return ViewCompat.onApplyWindowInsets(v, insets) } ͦΕͰ΋GJUT4ZTUFN8JOEPXTͰ͸Ͳ͏ʹ΋Ͱ͖ͳ͍ PS εςʔλεόʔͷྖҬʹESBX͍ͨ͠ ˞/BWJHBUJPO7JFXͷܧঝݩͰ͋Δ4DSJN*OTFUT'SBNF-BZPVU͕޷ྫ
  33. 33 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங wεςʔλεόʔͳͲͷαΠζΛΉ΍Έʹऔಘ͠Α͏ͱ ͤͣʹɺGJUT4ZTUFN8JOEPXTΛ׆༻͢΂͖ wෳࡶͳը໘Ͱ͸0O"QQMZ8JOEPX*OTFU-JTUFOFSͰ σϑΥϧτͷॲཧΛԣऔΓͨ͠ΓɺࣗલͰࢠ7JFXʹ ରͯ͠8JOEPX*OTFUTΛEJTQBUDI͢Δํ๏͕࢖͑Δ γεςϜ6*ͷ഑ஔʹӨڹ͞Εͳ͍ϨΠΞ΢τΛ૊Ήʹ͸ʁ 8JOEPX*OTFUTͷѻ͍Λ޻෉ͯ͠ γεςϜ6*ͷ഑ஔʹڧ͍ϨΠΞ΢τߏஙΛ

  34. ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ ͍ͭͯ 34

  35. 35 ը໘ͷঢ়ଶ͕ࣦΘΕΔ ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ

  36. 36 w΢Οϯυ΢αΠζͷมߋͳͲͷߏ੒ͷมߋ࣌ʹ͸ɹɹ ࣮ߦதͷ"DUJWJUZ'SBHNFOU͸࠶ੜ੒͞ΕΔ w৽͍͠ߏ੒༻ͷϦιʔεΛ࢖༻ͨ͠දࣔʹ੾Γସ͑ ΔͷΛࢧԉ͢ΔͨΊͷσϑΥϧτͷڍಈ wBOESPJEDPOGJH$IBOHFTΛࢦఆ͢Δ͜ͱͰࣗલ Ͱ΋؅ཧͰ͖Δ ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ ߏ੒ͷมߋΛލ͍Ͱը໘ঢ়ଶʹؔ͢ΔσʔλΛ ద੾ʹอ࣋͢Δ͜ͱ͕ཁٻ͞ΕΔ

  37. 37 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ "OESPJE%FWFMPQFST ʮ)BOEMJOH$POGJHVSBUJPO$IBOHFTʯ

  38. 38 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ ᶃ PO4BWF*OTUBODF4UBUF Ͱ#VOEMFʹ֨ೲ͠ɺ PO$SFBUF PO3FTUPSF*OTUBODF4UBUF Ͱ෮ݩ ᶄ TFU3FUBJO*OTUBODF

    USVF Λݺͼग़ͨ͠'SBHNFOU ʹσʔλΛ֨ೲ "OESPJE%FWFMPQFST ʮ)BOEMJOH$POGJHVSBUJPO$IBOHFTʯ
  39. 39 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ ᶃPO4BWF*OTUBODF4UBUF Ͱอ࣋ class ExampleActivity: AppCompatActivity() { private var

    foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) foo = savedInstanceState?.getParcelable("foo") } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putParcelable("foo", foo) } }
  40. ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ 40 wγϦΞϥΠζɾσγϦΞϥΠζΛ൐͍ɺϝϞϦফඅɾ ଎౓ͷ໘Ͱίετ͕େ͖͍ͷͰɺଟྔͷσʔλΛอ࣋ ͢Δ༻్ʹ͸޲͔ͳ͍ wߏ੒ͷมߋதʹ΋ঢ়ଶ͕มΘΓ͏Δεςʔτϑϧͳɹ ΦϒδΣΫτͷอ࣋ʹ͸࢖༻Ͱ͖ͳ͍ wωοτϫʔΫ઀ଓͷܧଓͳͲʹ͸༻͍ʹ͍͘ ᶃPO4BWF*OTUBODF4UBUF Ͱอ࣋

  41. ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ 41 w4DSPMM7JFX:ํ޲ͷεΫϩʔϧҐஔΛอ࣋ w5FYU7JFXBOESPJEGSFF[FT5FYU͕USVFͳ৔߹ʹɹɹ ςΩετΛอ࣋ʢ&EJU5FYU͸σϑΥϧτͰUSVFʣ w$PNQPVOE#VUUPODIFDLFEͰ͋Δ͔Λอ࣋ ᶃPO4BWF*OTUBODF4UBUF Ͱอ࣋ Ұ෦ͷ7JFX͸ࣗલͰঢ়ଶΛอ࣋͢Δ ʢ˞֤7JFXͷPO4BWF*OTUBODF4UBUF

    ͷ࣮૷ࢀরʣ
  42. 42 ᶃPO4BWF*OTUBODF4UBUF Ͱอ࣋ "OESPJEҎ߱ͰଟྔͷσʔλΛอ࣋͢Δͱ 5SBOTBDUJPO5PP-BSHF&YDFQUJPO͕UISPX͞ΕΔ ʢ"OESPJE#FIBWJPS$IBOHFTʣ ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ

  43. HVBSEJBOUPPMBSHFUPPM IUUQTHJUIVCDPNHVBSEJBOUPPMBSHFUPPM 43 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ

  44. 44 ᶄ'SBHNFOUTFU3FUBJO*OTUBODF USVF Λ༻͍ͯอ࣋ class ExampleActivity: AppCompatActivity() { private var

    retainedFragment: RetainedFragment? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) retainedFragment = getSupportFragmentManager() .findFragmentByTag(“tag") as? RetainedFragment if (retainedFragment == null) { // লུ: RetainedFragmentͷΠϯελϯεΛੜ੒ˍcommit } } } class RetainedFragment: Fragment() { var foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setRetainInstance(true) } } ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ
  45. ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ 45 ᶄ'SBHNFOUTFU3FUBJO*OTUBODF USVF Λ༻͍ͯอ࣋ wγϦΞϥΠζɾσγϦΞϥΠζΛ൐Θͳ͍ͨΊɺɹɹ εςʔτϑϧͳΦϒδΣΫτͷอ࣋ʹ࢖༻Ͱ͖Δ w"SDIJUFDUVSF$PNQPOFOUTͷ7JFX.PEFM΋ TFU3FUBJO*OTUBODF USVF

    Λݺͼग़ͨ͠'SBHNFOU Ͱอ࣋͞Ε͍ͯΔ ˞BOESPJEBSDIMJGFDZDMF)PMEFS'SBHNFOUࢀর
  46. 46 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ ඇਪ঑ʜʁ PO3FUBJO$VTUPN/PO$POGJHVSBUJPO*OTUBODF Ͱอ࣋ class ExampleActivity: AppCompatActivity() { private

    var foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) foo = getLastCustomNonConfigurationInstance() as? Foo } override fun onRetainCustomNonConfigurationInstance(): Any? { return foo } }
  47. 47 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ w"OESPJEY࣌୅·Ͱਪ঑͞Ε͍ͯͨํ๏ w"DUJWJUZPO3FUBJO/PO$POGJHVSBUJPO*OTUBODF ͷEFQSFDBUFE͕"OESPJE͔Β֎͞Ε͍ͯΔ͕ɺ جຊతʹ͸Ҿ͖ଓ͖'SBHNFOUΛ༻͍Δํ๏͕ਪ঑͞ Ε͍ͯΔ ˞IUUQTHJUIVCDPNBPTQNJSSPSQMBUGPSN@GSBNFXPSLT@CBTFDPNNJUDEGCD ͓Αͼ"DUJWJUZHFU-BTU/PO$POGJHVSBUJPO*OTUBODFͷ+BWBEPDࢀর ඇਪ঑ʜʁ

    PO3FUBJO$VTUPN/PO$POGJHVSBUJPO*OTUBODF Ͱอ࣋
  48. ᶃ PO4BWF*OTUBODF4UBUF Ͱ#VOEMFʹ֨ೲ͠ɺ PO$SFBUF PO3FTUPSF*OTUBODF4UBUF Ͱ෮ݩ ᶄ TFU3FUBJO*OTUBODF USVF Λݺͼग़ͨ͠'SBHNFOU

    ʹσʔλΛ֨ೲ 48 ࢖͍෼͚Λߟ͑Δ্Ͱ஫ҙ͢΂͖ͳͷ͸ อ࣋ͨ͠σʔλͷʮण໋ʯ ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ
  49. 49 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ PO4BWF*OTUBODF4UBUFͰอ࣋ TFU3FUBJO*OTUBODF USVF Λ ݺͼग़ͨ͠'SBHNFOUͰอ࣋ ʲࢀߟʳ"QQMJDBUJPOΫϥε΍ γϯάϧτϯͰอ࣋ ߏ੒ͷมߋ

    ʢը໘ճసɾ΢Οϯυ΢αΠζͷมߋʣ "DUJWJUZͷഁغ ϓϩηεͷഁغ
  50. 50 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ ᶃ PO4BWF*OTUBODF4UBUF Ͱ#VOEMFʹ֨ೲ͠ɺ PO$SFBUF PO3FTUPSF*OTUBODF4UBUF Ͱ෮ݩ ᶄ TFU3FUBJO*OTUBODF

    USVF Λݺͼग़ͨ͠'SBHNFOU ʹσʔλΛ֨ೲ "DUJWJUZͷഁغͱͱ΋ʹফࣦ͢Δ͕ɺ ଟྔͰεςʔτϑϧͳσʔλΛอ࣋Ͱ͖Δ "DUJWJUZͷελοΫ͕ଘࡏ͢ΔݶΓ࢒Γଓ͚Δ͕ɺ γϦΞϧԽՄೳͳগྔͷσʔλͷΈอ࣋Ͱ͖Δ
  51. ը໘ͷঢ়ଶอ࣋ͷख๏Λ Ͳ͏ޮՌతʹ࢖͍෼͚Δ͔ 51

  52. 52 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ڈ೥·ͰͷϑϦϧ Կ΋͔΋PO4BWF*OTUBODF4UBUF Ͱอ࣋

  53. 53 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ UBSHFU4EL7FSTJPOΛʹҾ্͖͛Δͱʜ ʢ˞5SBOTBDUJPO5PP-BSHF&YDFQUJPOʣ

  54. 54 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ͜Ε͔ΒͷϑϦϧ΋ͱ͍ϥΫϚ ϙϦγʔΛ࣋ͬͯঢ়ଶอ࣋ͷख๏Λ࢖͍෼͚Δ

  55. 55 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ෮ݩՄೳ ෮ݩෆೳ ݕࡧ݁Ռ ৽ண঎඼Ұཡ ʢλΠϜϥΠϯʣ ग़඼தͷೖྗ಺༰ ͓஌Βͤ ৄࡉݕࡧͷ৚݅

    ฤूதͷϓϩϑΟʔϧ PO4BWF*OTUBODF4UBUF Ͱ อ࣋ TFU3FUBJO*OTUBODF USVF Λ ݺͼग़ͨ͠'SBHNFOUͰอ࣋
  56. 56 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ෮ݩՄೳ ෮ݩෆೳ PO4BWF*OTUBODF4UBUF Ͱ อ࣋ TFU3FUBJO*OTUBODF USVF Λ

    ݺͼग़ͨ͠'SBHNFOUͰอ࣋ w՝୊ᶃ௿͍ίετͰޮ཰తʹ'SBHNFOUΛ࢖༻͢Δ ঢ়ଶอ࣋ͷํ๏ʹҠߦ͍ͨ͠ w՝୊ᶄͭͷը໘Ͱण໋͕ҟͳΔͭͷঢ়ଶอ࣋ͷ ख๏Λ༻͍ͨ࣌ͷ੔߹ੑΛ୲อ͍ͨ͠
  57. 57 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ՝୊ᶃ௿͍ίετͰޮ཰తʹ'SBHNFOUΛ࢖༻͢Δ ঢ়ଶอ࣋ͷํ๏ʹҠߦ͍ͨ͠ ͜Ε·Ͱ͸΄΅શͯͷը໘ͰGSBOLJFTBSEP*DFQJDLΛ࢖༻ IUUQTHJUIVCDPNGSBOLJFTBSEPJDFQJDL class ExampleActivity: AppCompatActivity() {

    @JvmField @State var foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Icepick.restoreInstanceState(this, savedInstanceState) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) Icepick.saveInstanceState(this, outState) } }
  58. 58 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ OBLBNVVV3FUBJOFS IUUQTHJUIVCDPNOBLBNVVVSFUBJOFS

  59. 59 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ՝୊ᶃ௿͍ίετͰޮ཰తʹ'SBHNFOUΛ࢖༻͢Δ ঢ়ଶอ࣋ͷํ๏ʹҠߦ͍ͨ͠ class ExampleActivity: AppCompatActivity() { @JvmField @Retain

    var foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Retainer.bind(this) } } "OOPUBUJPO1SPDFTTPSͰ*DFQJDLͷΑ͏ʹ ϑΟʔϧυͷอ࣋Λߦ͑ΔϥΠϒϥϦΛ࡞੒
  60. 60 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ 7JFX.PEFM "SDIJUFDUVSF$PNQPOFOUT ՝୊ᶄͭͷը໘Ͱण໋͕ҟͳΔͭͷঢ়ଶอ࣋ͷɹ ख๏Λ༻͍ͨ࣌ͷ੔߹ੑΛ୲อ͍ͨ͠ w"DUJWJUZ'SBHNFOU͔Β6*ʹؔΘΒͳ͍ϩδοΫ ΛҾ͖ണ͕͠ɺςελϏϦςΟΛ୲อͰ͖Δͷ͕ར఺ wPO4BWF*OTUBODF4UBUF Ͱͷอ࣋ɾ෮ݩͷ੹೚΋

    Ͱ͖ΔݶΓ7JFX.PEFMʹԡ͜͠Έ͍ͨʜ
  61. ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ 61 TBWFE*OTUBODF4UBUFΛੜ੒࣌ʹ౉ͤΔ 7JFX.PEFM'BDUPSZΛ࡞੒ ˞IUUQTQSPBOESPJEEFWDPNDVTUPNJ[JOHUIFOFXWJFXNPEFMDGCBDGDࢀߟ abstract class StateAwareViewModel(app: Application) :

    AndroidViewModel(app) { abstract fun saveInstanceState(outState: Bundle) abstract fun restoreInstanceState(state: Bundle?) } class StateAwareViewModelFactory( private val application: Application, private val savedInstanceState: Bundle? ) : ViewModelProvider.NewInstanceFactory() { override fun <T : ViewModel> create(modelClass: Class<T>): T { return if (StateAwareViewModel::class.java.isAssignableFrom(modelClass)) { return modelClass.getConstructor(Application::class.java) .newInstance(application) .also { (it as StateAwareViewModel) .restoreInstanceState(savedInstanceState) } } else super.create(modelClass) } }
  62. 62 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ՝୊ᶄͭͷը໘Ͱण໋͕ҟͳΔͭͷঢ়ଶอ࣋ͷɹ ख๏Λ༻͍ͨ࣌ͷ੔߹ੑΛ୲อ͍ͨ͠ TBWFE*OTUBODF4UBUF͔Βద੾ʹঢ়ଶ͕෮ݩͤ͞Δ͔ 7JFX.PEFMଆͷςετͰ୲อͰ͖Δ w7JFX.PEFMTBWFE*OTUBODF4UBUFͱ΋อ࣋͞Ε͍ͯΔέʔε wTBWFE*OTUBODF4UBUFͷΈ͕อ࣋͞Ε͍ͯΔέʔε TBWFE*OTUBODF4UBUFΛੜ੒࣌ʹ౉ͤΔ 7JFX.PEFM'BDUPSZΛ࡞੒

  63. ·ͱΊ 63

  64. 64 ·ͱΊ wGJUT4ZTUFN8JOEPXT8JOEPX*OTFUTΛ׆༻͠ɺ γεςϜ6*ͷ഑ஔʹӨڹ͞Εͳ͍ϨΠΞ΢τΛ૊Ή wը໘ͷঢ়ଶอ࣋ͷख๏ΛޮՌతʹ࢖͍෼͚ͯߏ੒ͷɹ มߋʹڧ͍ը໘Λߏங͢Δ ʰ΢Οϯυ΢αΠζͷมߋʹڧ͍ݎ࿚ͳը໘ʱͰ ΑΓ"OESPJEΒ͍͠ߴ඼࣭ͳΞϓϦΛ ଟ࠼ͳը໘αΠζɺϚϧν΢Οϯυ΢͸"OESPJEͷಛ৭ʜ

  65. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ