Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
How to keep data between orientation changes
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Masaki Ogata
April 20, 2017
Programming
7
2.6k
How to keep data between orientation changes
AbemaTVで実装している画面回転を支えるデータ保持についての話
Masaki Ogata
April 20, 2017
Tweet
Share
More Decks by Masaki Ogata
See All by Masaki Ogata
Jetpack Composeで始めるServer Cache State
ogaclejapan
2
280
AbemaTVを支えるアプリの優しさ / abematv_devcon_2017
ogaclejapan
3
6.8k
Architecture Components - Lifecycle library
ogaclejapan
3
2.8k
Your app name
ogaclejapan
1
2.9k
Flux de Relax :)
ogaclejapan
13
62k
Dagger2 has been released!
ogaclejapan
3
3.3k
Other Decks in Programming
See All in Programming
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
7
2.3k
Oxlint JS plugins
kazupon
1
940
QAフローを最適化し、品質水準を満たしながらリリースまでの期間を最短化する #RSGT2026
shibayu36
2
4.4k
AWS re:Invent 2025参加 直前 Seattle-Tacoma Airport(SEA)におけるハードウェア紛失インシデントLT
tetutetu214
2
110
コントリビューターによるDenoのすゝめ / Deno Recommendations by a Contributor
petamoriken
0
200
開発者から情シスまで - 多様なユーザー層に届けるAPI提供戦略 / Postman API Night Okinawa 2026 Winter
tasshi
0
200
疑似コードによるプロンプト記述、どのくらい正確に実行される?
kokuyouwind
0
380
AI によるインシデント初動調査の自動化を行う AI インシデントコマンダーを作った話
azukiazusa1
1
730
Automatic Grammar Agreementと Markdown Extended Attributes について
kishikawakatsumi
0
190
MUSUBIXとは
nahisaho
0
130
CSC307 Lecture 04
javiergs
PRO
0
660
CSC307 Lecture 01
javiergs
PRO
0
690
Featured
See All Featured
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
1
120
Utilizing Notion as your number one productivity tool
mfonobong
3
220
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.3k
Side Projects
sachag
455
43k
Exploring anti-patterns in Rails
aemeredith
2
250
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
270
BBQ
matthewcrist
89
10k
GitHub's CSS Performance
jonrohan
1032
470k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
The Power of CSS Pseudo Elements
geoffreycrofte
80
6.2k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Technical Leadership for Architectural Decision Making
baasie
1
240
Transcript
CA.apk #2 @CyberAgent Masaki Ogata ը໘ճసΛࢧ͑Δσʔλอ࣋ :)
ࣗݾհ Masaki Ogata CyberAgent, Inc. / AbemaTV, Inc. ogaclejapan @ogaclejapan
New
20174݄11ൃച ࢁށໜथɼࡔాߊҰɼࠇ༸ɼ౻ా ୖຏɼࢁాߤɼాࡔெɼ۽୩ࢠɼ ຊརതɼࡔຊେɼখܗণथɼླ େوɼࢤำါلɹஶ B5ʗ192ϖʔδ ఆՁʢຊମ1,980ԁʴ੫ʣ ISBN 978-4-7741-8863-8 https://goo.gl/Jcy3lJ
New
ը໘ճసΛࢧ͑Δσʔλอ࣋ :) by AbemaTV
2017/4 ॎରԠϦϦʔε͠·ͨ͠
Կ͕มΘͬͨͷ͔ʁ
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="tv.abema" > ... <activity android:name=".components.activity.MainActivity" android:configChanges="orientation|keyboardHidden| screenSize" android:screenOrientation="sensorLandscape"
android:theme="..." /> ... </manifest> AndroidManifest.xml
AndroidManifest.xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="tv.abema" > ... <activity android:name=".components.activity.MainActivity" android:configChanges="orientation|keyboardHidden| screenSize"
android:screenOrientation="sensorLandscape" android:theme="..." /> ... </manifest>
AndroidManifest.xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="tv.abema" > ... <activity android:name=".components.activity.MainActivity" android:screenOrientation="behind" android:theme="..."
/> ... </manifest>
Activity࠶ੜͱ ৽͍͠ੜ׆࢝Ί·ͨ͠$
ཧ༝̍ɿॎʗԣͰ࠷దͳUIΛ࣮ݱ͍ͨ͠
ཧ༝̎ɿMultiWindowʹରԠ͍ͨ͠
Activity࠶ੜԿ͕ͳͷ͔ʁ
Activity࠶ੜͷɿ • ϨΠΞτঢ়ଶͷ෮ݩ ʢChannelɺFullscreenɺ…ʣ • αʔόʔ͔Βऔಘͨ͠σʔλͷ࠶ར༻ • ॎʗԣͷը໘Γସ͑ͷγʔϜϨε͞
ҰൠతͳΞϓϩʔν
onSaveInstanceState(..)ͰBundleอଘ public class MainActivity extends AppCompatActivity { @Override protected void
onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable("foo", foo); ... } @Override protected void onCreate(Bundle savedInstanceState) { ... if (savedInstanceState != null) { Foo foo = savedInstanceState.getParcelable("foo"); }
(‘A`)ΫιΊΜͲͤ͐͘ʔʂ
AbemaTVͷΞϓϩʔν
onRetainCustomNonConfigurationInstance()ͰObjectฦ͢ public class MainActivity extends AppCompatActivity { @Override public Object
onRetainCustomNonConfigurationInstance() { return foo; } @Override protected void onCreate(Bundle savedInstanceState) { ... Object obj = getLastCustomNonConfigurationInstance(); if (obj instanceof Foo) { Foo foo = (Foo) obj; }
͜Εͩ! ! ‷( ŋŷŋ)و ̑̑ ŞƄŕ !
ͪΐͬ͜ͱιʔείʔυΛͬͯΈͨ
FragmentActivity.java public Object onRetainCustomNonConfigurationInstance() { return null; } @Override public
final Object onRetainNonConfigurationInstance() { ... Object custom = onRetainCustomNonConfigurationInstance(); ... NonConfigurationInstances nci = new NonConfigurationInstances(); nci.custom = custom; nci.fragments = fragments; nci.loaders = loaders; return nci; }
Activity.java public Object onRetainNonConfigurationInstance() { return null; } NonConfigurationInstances retainNonConfigurationInstances()
{ Object activity = onRetainNonConfigurationInstance(); ... NonConfigurationInstances nci = new NonConfigurationInstances(); nci.activity = activity; nci.children = children; nci.fragments = fragments; nci.loaders = loaders; ... return nci; }
ActivityThread.java public final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing) { return
performDestroyActivity(token, finishing, 0, false); } private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance) { ActivityClientRecord r = mActivities.get(token); ... if (getNonConfigInstance) { try { r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances(); ...
ActivityThread.java private void handleRelaunchActivity(ActivityClientRecord tmp) { ... handleDestroyActivity(r.token, false, configChanges,
true); ... ... handleLaunchActivity(r, currentIntent, ".."); ... } private Activity performLaunchActivity(...) { activity.attach(appContext, ..., r.lastNonConfigurationInstances, ...); ... r.lastNonConfigurationInstances = null;
Configuration ChangeʹΑΔ Activity࠶ੜ࣌ͷΈ෮ݩՄೳ
AbemaTVͰ Ͳ͏࣮͍ͯ͠Δͷ͔ʁ
AbemaTVͷΞʔΩςΫνϟɿ https://speakerdeck.com/ogaclejapan/flux-de-relax
AbemaTVͷFluxΞʔΩςΫνϟɿ
ը໘ճసͰഁغͤ͞ͳ͍DaggerͷComponentΛؚΊΔ @Override public ScreenComponent getScreenComponent() { if (screenComponent == null)
{ ScreenInstance retainedInstance = (ScreenInstance) getLastCustomNonConfigurationInstance(); if (retainedInstance == null) { ... screenComponent = Components.forApp(this).plus(...); } else { screenComponent = retainedInstance.component; } } return screenComponent; } @Override public Object onRetainCustomNonConfigurationInstance() { return new ScreenInstance(screenComponent, ...); }
AbemaTVͷDIίϯϙʔωϯτߏɿ AppComponent: ʢશମʣ ScreenComponent: ʢը໘୯Ґʣ ActivityComponent: ʢը໘୯Ґʣ ը໘ճసΛӽ͑ͯσʔλΛอ࣋͢ΔͨΊʹ ScreenίϯϙʔωϯτΛՃɻ
Activity࠶ੜͷɿ •ϨΠΞτঢ়ଶͷ෮ݩ ʢChannelɺFullscreenɺ…ʣ • αʔόʔ͔Βऔಘͨ͠σʔλͷ࠶ར༻ • ॎʗԣͷը໘Γସ͑ͷγʔϜϨε͞
͓ΘΓʹ /** * Return the value previously returned from *
{@link #onRetainCustomNonConfigurationInstance()}. */ @SuppressWarnings("deprecation") public Object getLastCustomNonConfigurationInstance() { NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); return nc != null ? nc.custom : null; } d..deprecation!??
͞ͱϦεΫࢴҰॏ