Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to keep data between orientation changes

How to keep data between orientation changes

AbemaTVで実装している画面回転を支えるデータ保持についての話

Masaki Ogata

April 20, 2017
Tweet

More Decks by Masaki Ogata

Other Decks in Programming

Transcript

  1. CA.apk #2 @CyberAgent
    Masaki Ogata
    ը໘ճసΛࢧ͑Δσʔλอ࣋ :)

    View Slide

  2. ࣗݾ঺հ
    Masaki Ogata
    CyberAgent, Inc. / AbemaTV, Inc.
    ogaclejapan
    @ogaclejapan
    New

    View Slide

  3. 2017೥4݄11೔ൃച
    ࢁށໜथɼࡔాߊҰɼࠇ઒༸ɼ౻ా
    ୖຏɼࢁాߤɼాࡔ࿨ெɼ۽୩஌ࢠɼ
    ৿ຊརതɼࡔຊ࿨େɼখܗণथɼླ
    ໦େوɼࢤำါلɹஶ
    B5൑ʗ192ϖʔδ
    ఆՁʢຊମ1,980ԁʴ੫ʣ
    ISBN 978-4-7741-8863-8
    https://goo.gl/Jcy3lJ
    New

    View Slide

  4. ը໘ճసΛࢧ͑Δσʔλอ࣋ :)
    by AbemaTV

    View Slide

  5. 2017/4 ॎରԠϦϦʔε͠·ͨ͠

    View Slide

  6. Կ͕มΘͬͨͷ͔ʁ

    View Slide

  7. 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

    View Slide

  8. AndroidManifest.xml
    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="..."
    />
    ...

    View Slide

  9. AndroidManifest.xml
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="tv.abema"
    >
    ...
    android:name=".components.activity.MainActivity"
    android:screenOrientation="behind"
    android:theme="..."
    />
    ...

    View Slide

  10. Activity࠶ੜ੒ͱ
    ৽͍͠ੜ׆࢝Ί·ͨ͠$

    View Slide

  11. ཧ༝̍ɿॎʗԣͰ࠷దͳUIΛ࣮ݱ͍ͨ͠

    View Slide

  12. ཧ༝̎ɿMultiWindowʹରԠ͍ͨ͠

    View Slide

  13. Activity࠶ੜ੒͸Կ͕໰୊ͳͷ͔ʁ

    View Slide

  14. Activity࠶ੜ੒ͷ໰୊఺ɿ
    • ϨΠΞ΢τঢ়ଶͷ෮ݩ

    ʢChannelɺFullscreenɺ…ʣ
    • αʔόʔ͔Βऔಘͨ͠σʔλͷ࠶ར༻
    • ॎʗԣͷը໘੾Γସ͑ͷγʔϜϨε͞

    View Slide

  15. ҰൠతͳΞϓϩʔν

    View Slide

  16. 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");
    }

    View Slide

  17. (‘A`)ΫιΊΜͲͤ͐͘ʔʂ

    View Slide

  18. AbemaTVͷΞϓϩʔν

    View Slide

  19. 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;
    }

    View Slide

  20. ͜Εͩ! ! ‷( ŋŷŋ)و ̑̑ ŞƄŕ !

    View Slide

  21. ͪΐͬ͜ͱιʔείʔυΛ௥ͬͯΈͨ

    View Slide

  22. 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;
    }

    View Slide

  23. 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;
    }

    View Slide

  24. 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();
    ...

    View Slide

  25. 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;

    View Slide

  26. Configuration ChangeʹΑΔ
    Activity࠶ੜ੒࣌ͷΈ෮ݩՄೳ

    View Slide

  27. AbemaTVͰ͸
    Ͳ͏࣮૷͍ͯ͠Δͷ͔ʁ

    View Slide

  28. AbemaTVͷΞʔΩςΫνϟɿ
    https://speakerdeck.com/ogaclejapan/flux-de-relax

    View Slide

  29. AbemaTVͷFluxΞʔΩςΫνϟɿ

    View Slide

  30. ը໘ճసͰഁغͤ͞ͳ͍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, ...);
    }

    View Slide

  31. AbemaTVͷDIίϯϙʔωϯτߏ੒ɿ
    AppComponent: ʢશମʣ
    ScreenComponent: ʢը໘୯Ґʣ
    ActivityComponent: ʢը໘୯Ґʣ
    ը໘ճసΛӽ͑ͯσʔλΛอ࣋͢ΔͨΊʹ
    ScreenίϯϙʔωϯτΛ௥Ճɻ

    View Slide

  32. Activity࠶ੜ੒ͷ໰୊఺ɿ
    •ϨΠΞ΢τঢ়ଶͷ෮ݩ 

    ʢChannelɺFullscreenɺ…ʣ
    • αʔόʔ͔Βऔಘͨ͠σʔλͷ࠶ར༻
    • ॎʗԣͷը໘੾Γସ͑ͷγʔϜϨε͞

    View Slide

  33. ͓ΘΓʹ
    /**
    * 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!??

    View Slide

  34. ଎͞ͱϦεΫ͸ࢴҰॏ

    View Slide