AbemaTVで実装している画面回転を支えるデータ保持についての話
CA.apk #2 @CyberAgentMasaki Ogataը໘ճసΛࢧ͑Δσʔλอ࣋ :)
View Slide
ࣗݾհMasaki OgataCyberAgent, Inc. / AbemaTV, Inc.ogaclejapan@ogaclejapanNew
20174݄11ൃചࢁށໜथɼࡔాߊҰɼࠇ༸ɼ౻ాୖຏɼࢁాߤɼాࡔெɼ۽୩ࢠɼຊརതɼࡔຊେɼখܗণथɼླେوɼࢤำါلɹஶB5ʗ192ϖʔδఆՁʢຊମ1,980ԁʴ੫ʣISBN 978-4-7741-8863-8https://goo.gl/Jcy3lJNew
ը໘ճసΛࢧ͑Δσʔλอ࣋ :)by AbemaTV
2017/4 ॎରԠϦϦʔε͠·ͨ͠
Կ͕มΘͬͨͷ͔ʁ
xmlns:android="http://schemas.android.com/apk/res/android"package="tv.abema">...android:name=".components.activity.MainActivity"android:configChanges="orientation|keyboardHidden|screenSize"android:screenOrientation="sensorLandscape"android:theme="..."/>...AndroidManifest.xml
AndroidManifest.xmlxmlns:android="http://schemas.android.com/apk/res/android"package="tv.abema">...android:name=".components.activity.MainActivity"android:configChanges="orientation|keyboardHidden|screenSize"android:screenOrientation="sensorLandscape"android:theme="..."/>...
AndroidManifest.xmlxmlns:android="http://schemas.android.com/apk/res/android"package="tv.abema">...android:name=".components.activity.MainActivity"android:screenOrientation="behind"android:theme="..."/>...
Activity࠶ੜͱ৽͍͠ੜ׆࢝Ί·ͨ͠$
ཧ༝̍ɿॎʗԣͰ࠷దͳUIΛ࣮ݱ͍ͨ͠
ཧ༝̎ɿMultiWindowʹରԠ͍ͨ͠
Activity࠶ੜԿ͕ͳͷ͔ʁ
Activity࠶ੜͷɿ• ϨΠΞτঢ়ଶͷ෮ݩ ʢChannelɺFullscreenɺ…ʣ• αʔόʔ͔Βऔಘͨ͠σʔλͷ࠶ར༻• ॎʗԣͷը໘Γସ͑ͷγʔϜϨε͞
ҰൠతͳΞϓϩʔν
onSaveInstanceState(..)ͰBundleอଘpublic class MainActivity extends AppCompatActivity {@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putParcelable("foo", foo);...}@Overrideprotected void onCreate(Bundle savedInstanceState) {...if (savedInstanceState != null) {Foo foo = savedInstanceState.getParcelable("foo");}
(‘A`)ΫιΊΜͲͤ͐͘ʔʂ
AbemaTVͷΞϓϩʔν
onRetainCustomNonConfigurationInstance()ͰObjectฦ͢public class MainActivity extends AppCompatActivity {@Overridepublic Object onRetainCustomNonConfigurationInstance() {return foo;}@Overrideprotected void onCreate(Bundle savedInstanceState) {...Object obj = getLastCustomNonConfigurationInstance();if (obj instanceof Foo) {Foo foo = (Foo) obj;}
͜Εͩ! ! ‷( ŋŷŋ)و ̑̑ ŞƄŕ !
ͪΐͬ͜ͱιʔείʔυΛͬͯΈͨ
FragmentActivity.javapublic Object onRetainCustomNonConfigurationInstance() {return null;}@Overridepublic final Object onRetainNonConfigurationInstance() {...Object custom = onRetainCustomNonConfigurationInstance();...NonConfigurationInstances nci = newNonConfigurationInstances();nci.custom = custom;nci.fragments = fragments;nci.loaders = loaders;return nci;}
Activity.javapublic Object onRetainNonConfigurationInstance() {return null;}NonConfigurationInstances retainNonConfigurationInstances() {Object activity = onRetainNonConfigurationInstance();...NonConfigurationInstances nci = newNonConfigurationInstances();nci.activity = activity;nci.children = children;nci.fragments = fragments;nci.loaders = loaders;...return nci;}
ActivityThread.javapublic final ActivityClientRecordperformDestroyActivity(IBinder token, boolean finishing) {return performDestroyActivity(token, finishing, 0, false);}private ActivityClientRecord performDestroyActivity(IBindertoken, boolean finishing,int configChanges, boolean getNonConfigInstance) {ActivityClientRecord r = mActivities.get(token);...if (getNonConfigInstance) {try {r.lastNonConfigurationInstances=r.activity.retainNonConfigurationInstances();...
ActivityThread.javaprivate 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 ObjectonRetainCustomNonConfigurationInstance() {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!??
͞ͱϦεΫࢴҰॏ