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
Masaki Ogata
April 20, 2017
Programming
2.7k
7
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
How to keep data between orientation changes
AbemaTVで実装している画面回転を支えるデータ保持についての話
Masaki Ogata
April 20, 2017
More Decks by Masaki Ogata
See All by Masaki Ogata
Jetpack Composeで始めるServer Cache State
ogaclejapan
2
310
AbemaTVを支えるアプリの優しさ / abematv_devcon_2017
ogaclejapan
3
6.9k
Architecture Components - Lifecycle library
ogaclejapan
3
2.8k
Your app name
ogaclejapan
1
3k
Flux de Relax :)
ogaclejapan
13
62k
Dagger2 has been released!
ogaclejapan
3
3.4k
Other Decks in Programming
See All in Programming
AutonomyとControlのあいだ:Graflowで記述するAIエージェント協調
myui
0
110
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
220
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.6k
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
5k
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
4
2.1k
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
110
Lessons from Spec-Driven Development
simas
PRO
0
150
Technical Debt: Understanding it Rightly, Engaging it Rightly #LaravelLiveJP
shogogg
0
210
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
530
ユニットテストの先へ:テスト技法で要求・仕様を整理するJava開発実践 / Beyond_Unit_Testing_Practical_Java_Development_Techniques_for_Organizing_Requirements_and_Specifications
shimashima35
0
380
Webフレームワークの ベンチマークについて
yusukebe
0
150
The Arts and Crafts of Work in the AI Era — Toward Mastery in Software Development
kuranuki
1
740
Featured
See All Featured
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
300
WENDY [Excerpt]
tessaabrams
11
38k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
580
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
140
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
250
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
460
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
330
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
530
The Invisible Side of Design
smashingmag
302
52k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
220
Measuring & Analyzing Core Web Vitals
bluesmoon
9
860
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!??
͞ͱϦεΫࢴҰॏ