From f71883a2b9b158f7eed7c06d34e174874f8e7cf7 Mon Sep 17 00:00:00 2001 From: seven332 Date: Thu, 2 Jul 2015 16:57:52 +0800 Subject: [PATCH] Improve scene lifecycle --- .../ui/scene/AdvanceSettingsScene.java | 5 +- .../hippo/ehviewer/ui/scene/CommentScene.java | 27 +-- .../ui/scene/DisplaySettingsScene.java | 5 +- .../ehviewer/ui/scene/EHSettingsScene.java | 5 +- .../ehviewer/ui/scene/GalleryDetailScene.java | 6 +- .../ehviewer/ui/scene/GalleryListScene.java | 32 +-- .../ehviewer/ui/scene/MainSettingsScene.java | 12 +- .../hippo/ehviewer/ui/scene/SignInScene.java | 6 +- .../java/com/hippo/scene/AppbarScene.java | 6 +- .../main/java/com/hippo/scene/Curtain.java | 16 +- app/src/main/java/com/hippo/scene/Scene.java | 216 ++++++++++++------ .../java/com/hippo/scene/SceneManager.java | 162 ++++++++----- .../java/com/hippo/scene/SimpleDialog.java | 9 +- .../preference/PreferenceHeaderScene.java | 5 +- .../scene/preference/PreferenceScene.java | 5 +- 15 files changed, 307 insertions(+), 210 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/AdvanceSettingsScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/AdvanceSettingsScene.java index 6f30e857f..40e2f78db 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/AdvanceSettingsScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/AdvanceSettingsScene.java @@ -17,7 +17,6 @@ package com.hippo.ehviewer.ui.scene; import android.content.res.Resources; -import android.os.Bundle; import com.hippo.ehviewer.BuildConfig; import com.hippo.ehviewer.Constants; @@ -35,8 +34,8 @@ public class AdvanceSettingsScene extends PreferenceScene implements Preference. private static final boolean DEFAULT_SHOW_APPLICATION_STATS = BuildConfig.DEBUG; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); setTitle(R.string.settings); setIcon(R.drawable.ic_arrow_left_dark); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/CommentScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/CommentScene.java index c945ba393..098242544 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/CommentScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/CommentScene.java @@ -2,8 +2,6 @@ package com.hippo.ehviewer.ui.scene; import android.content.Context; import android.content.res.Resources; -import android.os.Bundle; -import android.support.annotation.Nullable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.Html; @@ -39,18 +37,9 @@ public class CommentScene extends AppbarScene { } @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - onCreateView(); - if (savedInstanceState == null) { - onBindView(); - } else { - onRestoreView(savedInstanceState); - } - } + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); - - private void onCreateView() { Context context = getStageActivity(); Resources resources = context.getResources(); @@ -73,12 +62,18 @@ public class CommentScene extends AppbarScene { mRecyclerView.setClipToPadding(false); } - private void onBindView() { + @Override + protected void onBind() { + super.onBind(); + handleAnnouncer(getAnnouncer()); } - private void onRestoreView(@Nullable Bundle savedInstanceState) { - // Empty + @Override + protected void onRestore() { + super.onRestore(); + + // mCommentList is already setted, nothing to do } @Override diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/DisplaySettingsScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/DisplaySettingsScene.java index 17d3b63c7..05e725896 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/DisplaySettingsScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/DisplaySettingsScene.java @@ -17,7 +17,6 @@ package com.hippo.ehviewer.ui.scene; import android.content.res.Resources; -import android.os.Bundle; import com.hippo.ehviewer.R; import com.hippo.scene.preference.Preference; @@ -28,8 +27,8 @@ import com.hippo.scene.preference.PreferenceSet; public class DisplaySettingsScene extends PreferenceScene { @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); setTitle(R.string.settings); setIcon(R.drawable.ic_arrow_left_dark); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/EHSettingsScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/EHSettingsScene.java index 937a908aa..7104fcb6c 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/EHSettingsScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/EHSettingsScene.java @@ -17,7 +17,6 @@ package com.hippo.ehviewer.ui.scene; import android.content.res.Resources; -import android.os.Bundle; import com.hippo.ehviewer.BuildConfig; import com.hippo.ehviewer.Constants; @@ -37,8 +36,8 @@ public final class EHSettingsScene extends PreferenceScene { EhClient.SOURCE_EX : EhClient.SOURCE_G; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); setTitle(R.string.settings); setIcon(R.drawable.ic_arrow_left_dark); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java index 01c0851c1..98ca72ee4 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java @@ -20,8 +20,6 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.res.Resources; import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.Nullable; import android.text.Html; import android.view.Gravity; import android.view.LayoutInflater; @@ -174,8 +172,8 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener, } @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); setContentView(R.layout.scene_gallery_detail); mDetailFrameLayout = (FrameLayout) findViewById(R.id.detail_frame_layout); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java index 5bb10b54c..70e9070e9 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java @@ -23,9 +23,7 @@ import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.drawable.Drawable; -import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.text.TextUtils; @@ -56,10 +54,10 @@ import com.hippo.ehviewer.util.EhUtils; import com.hippo.ehviewer.widget.ContentLayout; import com.hippo.ehviewer.widget.LoadImageView; import com.hippo.ehviewer.widget.OffsetLayout; -import com.hippo.ehviewer.widget.SimpleRatingView; import com.hippo.ehviewer.widget.SearchBar; import com.hippo.ehviewer.widget.SearchDatabase; import com.hippo.ehviewer.widget.SearchLayout; +import com.hippo.ehviewer.widget.SimpleRatingView; import com.hippo.scene.Announcer; import com.hippo.scene.Curtain; import com.hippo.scene.Scene; @@ -236,16 +234,16 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper, } @Override - protected void onRebirth(@Nullable Bundle savedInstanceState) { - super.onRebirth(savedInstanceState); + protected void onRebirth() { + super.onRebirth(); mGalleryListHelper = new GalleryListHelper(getStageActivity(), mGalleryListHelper); } @SuppressWarnings("deprecation") @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); setContentView(R.layout.scene_gallery_list); mActivity = (ContentActivity) getStageActivity(); @@ -310,14 +308,14 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper, mCornerFab.setDrawable(mAddDeleteDrawable); // When scene start - if (savedInstanceState == null) { + if (!rebirth) { handleAnnouncer(getAnnouncer()); } } @Override - protected void onDestroy() { - super.onDestroy(); + protected void onDie() { + super.onDie(); // Avoid memory leak if (mGalleryListHelper.mListener != null) { @@ -332,20 +330,6 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper, ((ContentActivity) getStageActivity()).setDrawerListActivatedPosition(mDrawerListActivatedPosition); } - @Override - protected void saveInstanceState(Bundle outState) { - super.saveInstanceState(outState); - - outState.putInt(KEY_STATE, mState); - } - - @Override - protected void restoreInstanceState(@NonNull Bundle savedInstanceState) { - super.restoreInstanceState(savedInstanceState); - - setState(savedInstanceState.getInt(KEY_STATE), false); - } - @Override protected void onGetFitPaddingBottom(int b) { // Content Layout diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/MainSettingsScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/MainSettingsScene.java index 9502085dc..6da994f32 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/MainSettingsScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/MainSettingsScene.java @@ -17,7 +17,6 @@ package com.hippo.ehviewer.ui.scene; import android.content.res.Resources; -import android.os.Bundle; import com.hippo.ehviewer.R; import com.hippo.ehviewer.ui.ContentActivity; @@ -27,17 +26,19 @@ import com.hippo.scene.preference.PreferenceHeaderScene; public final class MainSettingsScene extends PreferenceHeaderScene { @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); ((ContentActivity) getStageActivity()).setDrawerListActivatedPosition(ContentActivity.DRAWER_LIST_SETTINGS); setTitle(R.string.settings); setIcon(R.drawable.ic_arrow_left_dark); - Resources resources = getStageActivity().getResources(); + setPreferenceHeaders(getPreferenceHeaders()); + } - PreferenceHeader[] phs = new PreferenceHeader[] { + private PreferenceHeader[] getPreferenceHeaders() { + return new PreferenceHeader[] { newPreferenceHeader( R.drawable.ic_cellphone_android_theme_accent, R.string.settings_display, @@ -51,7 +52,6 @@ public final class MainSettingsScene extends PreferenceHeaderScene { R.string.settings_advance, AdvanceSettingsScene.class) }; - setPreferenceHeaders(phs); } @Override diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/SignInScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/SignInScene.java index 64b6939a1..d158a43b5 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/SignInScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/SignInScene.java @@ -16,8 +16,6 @@ package com.hippo.ehviewer.ui.scene; -import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.EditorInfo; @@ -61,8 +59,8 @@ public final class SignInScene extends Scene implements View.OnClickListener, } @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); setContentView(R.layout.scene_sign_in); mMainView = findViewById(R.id.sigin_in_main); diff --git a/app/src/main/java/com/hippo/scene/AppbarScene.java b/app/src/main/java/com/hippo/scene/AppbarScene.java index 2f3cb563f..f2b448e43 100644 --- a/app/src/main/java/com/hippo/scene/AppbarScene.java +++ b/app/src/main/java/com/hippo/scene/AppbarScene.java @@ -17,9 +17,7 @@ package com.hippo.scene; import android.graphics.drawable.Drawable; -import android.os.Bundle; import android.support.annotation.DrawableRes; -import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.view.View; import android.view.ViewGroup; @@ -53,8 +51,8 @@ public class AppbarScene extends Scene { } @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); super.setContentView(R.layout.scene_appbar); mIcon = (SimpleImageView) super.findViewById(R.id.appbar_icon); diff --git a/app/src/main/java/com/hippo/scene/Curtain.java b/app/src/main/java/com/hippo/scene/Curtain.java index 0e31ee970..11f85cfe9 100644 --- a/app/src/main/java/com/hippo/scene/Curtain.java +++ b/app/src/main/java/com/hippo/scene/Curtain.java @@ -18,9 +18,6 @@ package com.hippo.scene; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.view.View; - -import com.hippo.util.ViewUtils; public abstract class Curtain { @@ -38,6 +35,13 @@ public abstract class Curtain { return scene != null && scene.getId() == mPreviousSceneId; } + /** + * @return true if can NOT still run when previous scene changed + */ + protected boolean specifyPreviousScene() { + return true; + } + protected void onRebirth() { } @@ -62,7 +66,7 @@ public abstract class Curtain { public abstract boolean isInAnimation(); protected void dispatchOpenFinished(@NonNull Scene enter, @NonNull Scene exit) { - exit.openFinished(); + enter.openFinished(); } protected void dispatchCloseFinished(@NonNull Scene enter, @NonNull Scene exit) { @@ -70,10 +74,10 @@ public abstract class Curtain { } protected void hideSceneOnOpen(@NonNull Scene exit) { - ViewUtils.setVisibility(exit.getSceneView(), View.GONE); + exit.setHide(true); } protected void showSceneOnClose(@NonNull Scene enter) { - ViewUtils.setVisibility(enter.getSceneView(), View.VISIBLE); + enter.setHide(false); } } diff --git a/app/src/main/java/com/hippo/scene/Scene.java b/app/src/main/java/com/hippo/scene/Scene.java index fc2f76648..78f37a3f8 100644 --- a/app/src/main/java/com/hippo/scene/Scene.java +++ b/app/src/main/java/com/hippo/scene/Scene.java @@ -39,34 +39,38 @@ import com.hippo.util.ViewUtils; * When start a new {@code Scene}, previous {@code Scene} can stay at screen for * a while. Or retain for a while before destroy. */ -// TODO Improve state public abstract class Scene { public static final int LAUNCH_MODE_STANDARD = 0; public static final int LAUNCH_MODE_SINGLE_TOP = 1; - static final int SCENE_STATE_CREATE = 0; - static final int SCENE_STATE_RUN = 1; - static final int SCENE_STATE_DESTROY = 2; - static final int SCENE_STATE_OPEN = 3; + static final int SCENE_STATE_INIT = 0; + static final int SCENE_STATE_PREPARE = 1; + static final int SCENE_STATE_OPEN = 2; + static final int SCENE_STATE_RUN = 3; static final int SCENE_STATE_CLOSE = 4; - static final int SCENE_STATE_PAUSE = 5; + static final int SCENE_STATE_DESTROY = 5; + static final int SCENE_STATE_DIE = 6; + static final int SCENE_STATE_PAUSE = 7; + static final int SCENE_STATE_REBIRTH = 8; private @Nullable Curtain mCurtain; private @Nullable Announcer mAnnouncer; @SuppressWarnings("deprecation") - private @Nullable SceneView mSceneView; + private SceneView mSceneView; private int mBackgroundColor = 0xffeeeeee; // TODO Need a better to set background color - private int mState; + private int mState = SCENE_STATE_INIT; protected static SceneManager sSceneManager; private int mId; + private boolean mHide; + static void setSceneManager(SceneManager sceneManager) { sSceneManager = sceneManager; } @@ -106,11 +110,15 @@ public abstract class Scene { return LAUNCH_MODE_STANDARD; } + private void checkSceneView() { + AssertUtils.assertNotNull("Must call it after onCreate and before onDestroy", mSceneView); + } + /** * Must call it after onCreate and before onDestroy */ public @NonNull SceneView getSceneView() { - AssertUtils.assertNotNull("Must call it after onCreate and before onDestroy", mSceneView); + checkSceneView(); return mSceneView; } @@ -143,10 +151,37 @@ public abstract class Scene { sSceneManager.finishScene(this); } - void create(@Nullable Bundle savedInstanceState) { - onCreate(savedInstanceState); + void setHide(boolean hide) { + checkSceneView(); + mHide = hide; + if (hide) { + mSceneView.setVisibility(View.GONE); + } else { + mSceneView.setVisibility(View.VISIBLE); + } + } + + boolean getHide() { + return mHide; + } + + void init() { + onInit(); + } + + void rebirth() { + if (mCurtain != null) { + mCurtain.onRebirth(); + } + + onRebirth(); + } + + void create(boolean rebirth) { + onCreate(rebirth); if (mSceneView == null) { + // Not call setContentView in onCreate, create scene view by ourself mSceneView = createSceneView(getStageActivity()); initBackground(mSceneView); } @@ -155,24 +190,56 @@ public abstract class Scene { attachToStage(); // Hide it if it is hidden - if (savedInstanceState != null && savedInstanceState.getBoolean(getIsGoneKey(), false)) { + if (mHide) { + mSceneView.setVisibility(View.INVISIBLE); mSceneView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { ViewUtils.removeOnGlobalLayoutListener(mSceneView.getViewTreeObserver(), this); - ViewUtils.setVisibility(mSceneView, View.GONE); + mSceneView.setVisibility(View.GONE); } }); } } - // TODO Tell destory is it need close - void destroy() { - onDestroy(); + void bind() { + onBind(); + } + + void restore() { + onRestore(); + } + + void destroy(boolean die) { + // Make sure soft key broad is hidden + InputMethodManager imm = (InputMethodManager) getStageActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getSceneView().getWindowToken(), 0); + + onDestroy(die); + } + + void die(boolean keepView) { + onDie(); + + if (!keepView) { + detachFromeStage(); + } SceneApplication.getRefWatcher(getStageActivity()).watch(this); } + void pause() { + getSceneView().setEnableTouch(false); + + onPause(); + } + + void resume() { + getSceneView().setEnableTouch(true); + + onResume(); + } + void open() { onOpen(); } @@ -181,16 +248,48 @@ public abstract class Scene { onClose(); } - void pause() { - onPause(); + protected void onInit() { + } - void resume() { - onResume(); + protected void onRebirth() { + } - void rebirth(@Nullable Bundle savedInstanceState) { - onRebirth(savedInstanceState); + protected void onCreate(boolean rebirth) { + + } + + protected void onBind() { + + } + + protected void onRestore() { + + } + + protected void onDestroy(boolean die) { + + } + + protected void onDie() { + + } + + protected void onPause() { + + } + + protected void onResume() { + + } + + protected void onOpen() { + + } + + protected void onClose() { + } void setFitPaddingBottom(int b) { @@ -198,10 +297,21 @@ public abstract class Scene { } /** - * return true if it is close or about to close + * @return true if the scene is dead or will be */ - public boolean isFinishing() { - return mState == SCENE_STATE_CLOSE || mState == SCENE_STATE_DESTROY; + public boolean canNotBeSaved() { + return mState == SCENE_STATE_CLOSE || mState == SCENE_STATE_DESTROY || mState == SCENE_STATE_DIE; + } + + /** + * @return true if the scene is dead + */ + public boolean isDead() { + return mState == SCENE_STATE_DIE; + } + + public boolean isRunning() { + return mState == SCENE_STATE_RUN; } public void setBackgroundColor(int bgColor) { @@ -230,7 +340,8 @@ public abstract class Scene { StageActivity sa = getStageActivity(); mSceneView = createSceneView(sa); initBackground(mSceneView); - mSceneView.addView(view, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + mSceneView.addView(view, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } private void initBackground(@NonNull View bg) { @@ -240,38 +351,6 @@ public abstract class Scene { bg.requestFocus(); } - protected void onCreate(@Nullable Bundle savedInstanceState) { - } - - @SuppressWarnings("ConstantConditions") - protected void onDestroy() { - // Make sure soft key broad is hidden - if (mSceneView != null) { - InputMethodManager imm = (InputMethodManager) getStageActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(mSceneView.getWindowToken(), 0); - } - } - - protected void onOpen() { - } - - protected void onClose() { - } - - protected void onPause() { - getSceneView().setEnableTouch(false); - } - - protected void onResume() { - getSceneView().setEnableTouch(true); - } - - protected void onRebirth(@Nullable Bundle savedInstanceState) { - if (mCurtain != null) { - mCurtain.onRebirth(); - } - } - protected void onNewAnnouncer(Announcer announcer) { } @@ -369,16 +448,11 @@ public abstract class Scene { } void openFinished() { - open(); - setState(Scene.SCENE_STATE_RUN); + sSceneManager.openScene(this); } void closeFinished() { - sSceneManager.removeLegacyScene(this); - - close(); - setState(Scene.SCENE_STATE_DESTROY); - detachFromeStage(); + sSceneManager.closeScene(this); } // It is constant @@ -386,21 +460,13 @@ public abstract class Scene { return "scene:" + mId; } - private String getIsGoneKey() { - return getStateKey() + ":gone"; - } - - protected void saveInstanceState(Bundle outState) { + void saveInstanceState(Bundle outState) { SparseArray states = new SparseArray<>(); onSaveInstanceState(states); outState.putSparseParcelableArray(getStateKey(), states); - - if (mSceneView != null) { - outState.putBoolean(getIsGoneKey(), mSceneView.getVisibility() == View.GONE); - } } - protected void restoreInstanceState(@NonNull Bundle savedInstanceState) { + void restoreInstanceState(@NonNull Bundle savedInstanceState) { if (mSceneView != null) { SparseArray savedStates = savedInstanceState.getSparseParcelableArray(getStateKey()); diff --git a/app/src/main/java/com/hippo/scene/SceneManager.java b/app/src/main/java/com/hippo/scene/SceneManager.java index 158f4d4c1..1fdeda77e 100644 --- a/app/src/main/java/com/hippo/scene/SceneManager.java +++ b/app/src/main/java/com/hippo/scene/SceneManager.java @@ -17,14 +17,18 @@ package com.hippo.scene; import android.os.Bundle; +import android.os.Looper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import com.hippo.util.AssertUtils; import com.hippo.util.IntIdGenerator; import com.hippo.util.Log; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.Stack; public class SceneManager { @@ -34,7 +38,9 @@ public class SceneManager { private Stack mSceneStack = new Stack<>(); private StageActivity mStageActivity; - private Scene mLegacyScene; + private boolean mLegacySceneSetLock; + private Set mLegacySceneSet = new HashSet<>(); + private Set mPrepareToDieSceneSet = new HashSet<>(); private IntIdGenerator mIdGenerator = IntIdGenerator.create(); @@ -107,6 +113,19 @@ public class SceneManager { } } + private void checkLoop() { + if (Looper.myLooper() != Looper.getMainLooper()) { + throw new IllegalStateException("It is not main loop!"); + } + } + + private void checkPrepareToDie(Scene scene) { + if (mPrepareToDieSceneSet.contains(scene)) { + mPrepareToDieSceneSet.remove(scene); + finishScene(scene); + } + } + Scene createSceneByClass(@NonNull Class sceneClass) { try { return (Scene) sceneClass.newInstance(); @@ -123,12 +142,14 @@ public class SceneManager { // TODO check previousState state void startScene(@NonNull Class sceneClass, @Nullable Announcer announcer, @Nullable Curtain curtain) { + checkLoop(); + if (!isStageAlive()) { - Log.w(TAG, "Stage is not alive, but attemp to create " + sceneClass.getSimpleName()); - return; + throw new IllegalStateException("Stage is not alive, but attemp to create " + sceneClass.getSimpleName()); } - Scene topScene = getTopState(); + // check LAUNCH_MODE_SINGLE_TOP + Scene topScene = getTopScene(); if (sceneClass.isInstance(topScene) && topScene.getLaunchMode() == Scene.LAUNCH_MODE_SINGLE_TOP) { topScene.onNewAnnouncer(announcer); @@ -143,6 +164,8 @@ public class SceneManager { } void showDialog(@NonNull SceneDialog dialog, @Nullable Curtain curtain) { + checkLoop(); + if (!isStageAlive()) { Log.w(TAG, "Stage is not alive, but attemp to show dialog " + dialog.toString()); return; @@ -154,7 +177,7 @@ public class SceneManager { } private void startScene(Scene scene, Curtain curtain) { - Scene previousState = getTopState(); + Scene previousState = getTopScene(); mSceneStack.push(scene); if (curtain != null) { @@ -164,12 +187,12 @@ public class SceneManager { if (previousState != null) { previousState.pause(); previousState.setState(Scene.SCENE_STATE_PAUSE); - notifyPause(previousState.getClass()); } - scene.create(null); - scene.setState(Scene.SCENE_STATE_CREATE); - notifyCreate(scene.getClass()); + scene.init(); + scene.setState(Scene.SCENE_STATE_PREPARE); + scene.create(false); + scene.bind(); // Update fit padding int fitPaddingBottom = getStageActivity().getFitPaddingBottom(); @@ -183,65 +206,80 @@ public class SceneManager { // Set state run by curtain } else { scene.setState(Scene.SCENE_STATE_RUN); + checkPrepareToDie(scene); } } /** - * End legacy scene close animation at once + * End all legacy scene animation at once * * @return True if legacy scene exist and its curtain animation is running */ boolean endLegacyScene() { - if (mLegacyScene != null) { - boolean result = mLegacyScene.endCurtainAnimation(); - mLegacyScene = null; - return result; + if (!mLegacySceneSet.isEmpty()) { + mLegacySceneSetLock = true; + for (Scene scene : mLegacySceneSet) { + scene.endCurtainAnimation(); + } + mLegacySceneSetLock = false; + mLegacySceneSet.clear(); + return true; + } else { + return false; } - return false; } void finishScene(@NonNull Scene scene) { + checkLoop(); + int index = getSceneIndex(scene); if (index >= 0 && index < mSceneStack.size()) { + if (scene.canNotBeSaved()) { + // the scene is hopeless + scene.endCurtainAnimation(); + return; + } - endLegacyScene(); + if (!scene.isRunning()) { + // the scene prepare to die + mPrepareToDieSceneSet.add(scene); + scene.endCurtainAnimation(); + return; + } - // Scene state might be SCENE_STATE_RUN, SCENE_STATE_OPEN, SCENE_STATE_PAUSE - if (index == 0) { + // TODO If the cene is under a dialog, the previous may not show + if (index != mSceneStack.size() - 1 || index == 0) { // It is the last scene, just finish the activity mSceneStack.remove(index); - - scene.destroy(); + scene.destroy(true); scene.setState(Scene.SCENE_STATE_DESTROY); - notifyDestroy(scene.getClass()); + scene.die(index == 0); + scene.setState(Scene.SCENE_STATE_DIE); - getStageActivity().finish(); - } else { - // TODO check scene state - - mSceneStack.remove(index); - Scene previousState = getTopState(); - - // If Scene is CLOSE - - if (previousState != null) { - previousState.resume(); - previousState.setState(Scene.SCENE_STATE_RUN); - notifyResume(previousState.getClass()); + if (index == 0) { + getStageActivity().finish(); } + } else { + mSceneStack.remove(index); + Scene previousScene = mSceneStack.get(index - 1); - scene.destroy(); - scene.setState(Scene.SCENE_STATE_DESTROY); - notifyDestroy(scene.getClass()); + previousScene.resume(); + previousScene.setState(Scene.SCENE_STATE_RUN); + + scene.destroy(true); Curtain curtain = scene.getCurtain(); - if (curtain != null && previousState != null && curtain.isPreviousScene(previousState)) { + if (curtain != null && + (!curtain.specifyPreviousScene() || curtain.isPreviousScene(previousScene))) { scene.setState(Scene.SCENE_STATE_CLOSE); - mLegacyScene = scene; - curtain.close(previousState, scene); - // detachFromeStage by curtain + curtain.close(previousScene, scene); + // add the scene to legacy set + mLegacySceneSet.add(scene); + // curtain will kill the scene } else { - scene.detachFromeStage(); + scene.setState(Scene.SCENE_STATE_DESTROY); + scene.die(false); + scene.setState(Scene.SCENE_STATE_DIE); } } } else { @@ -249,9 +287,28 @@ public class SceneManager { } } - void removeLegacyScene(Scene scene) { - if (mLegacyScene == scene) { - mLegacyScene = null; + private void checkSceneState(Scene scene, int expected) { + AssertUtils.assertEquals("The scene state is " + scene.getState() + ", but it should be " + expected, + expected, scene.getState()); + } + + void openScene(Scene scene) { + checkSceneState(scene, Scene.SCENE_STATE_OPEN); + scene.open(); + scene.setState(Scene.SCENE_STATE_RUN); + checkPrepareToDie(scene); + } + + void closeScene(Scene scene) { + checkSceneState(scene, Scene.SCENE_STATE_CLOSE); + scene.close(); + scene.setState(Scene.SCENE_STATE_DESTROY); + scene.die(false); + scene.setState(Scene.SCENE_STATE_DIE); + + // remove the scene from legacy set + if (!mLegacySceneSetLock) { + mLegacySceneSet.remove(scene); } } @@ -266,7 +323,7 @@ public class SceneManager { } boolean onBackPressed() { - Scene scene = getTopState(); + Scene scene = getTopScene(); if (scene != null) { scene.onBackPressedInternal(); return true; @@ -276,7 +333,7 @@ public class SceneManager { } } - private Scene getTopState() { + private Scene getTopScene() { if (!mSceneStack.isEmpty()) { return mSceneStack.peek(); } else { @@ -296,10 +353,13 @@ public class SceneManager { protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { for (Scene scene : mSceneStack) { - // Recreate - scene.rebirth(savedInstanceState); - notifyRebirth(scene.getClass()); - scene.create(savedInstanceState); + scene.destroy(false); + scene.setState(Scene.SCENE_STATE_REBIRTH); + scene.rebirth(); + scene.setState(Scene.SCENE_STATE_PREPARE); + scene.create(true); + scene.restore(); + scene.setState(Scene.SCENE_STATE_RUN); scene.restoreInstanceState(savedInstanceState); } } diff --git a/app/src/main/java/com/hippo/scene/SimpleDialog.java b/app/src/main/java/com/hippo/scene/SimpleDialog.java index 82883d08c..0e6501e73 100644 --- a/app/src/main/java/com/hippo/scene/SimpleDialog.java +++ b/app/src/main/java/com/hippo/scene/SimpleDialog.java @@ -17,7 +17,6 @@ package com.hippo.scene; import android.content.Context; -import android.os.Bundle; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -72,8 +71,8 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener, } @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); // TODO setBackgroundColor(BACKGROUND_COLOR); @@ -103,8 +102,8 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener, } @Override - protected void onDestroy() { - super.onDestroy(); + protected void onDie() { + super.onDie(); OnCloseListener listener = mBuilder.mOnCloseListener; if (listener != null) { diff --git a/app/src/main/java/com/hippo/scene/preference/PreferenceHeaderScene.java b/app/src/main/java/com/hippo/scene/preference/PreferenceHeaderScene.java index 1884767ec..fc1ebdd38 100644 --- a/app/src/main/java/com/hippo/scene/preference/PreferenceHeaderScene.java +++ b/app/src/main/java/com/hippo/scene/preference/PreferenceHeaderScene.java @@ -16,7 +16,6 @@ package com.hippo.scene.preference; -import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -49,8 +48,8 @@ public class PreferenceHeaderScene extends AppbarScene { private List mHeaderList = new ArrayList<>(); @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); setContentView(R.layout.scene_preference_header); mActivity = getStageActivity(); diff --git a/app/src/main/java/com/hippo/scene/preference/PreferenceScene.java b/app/src/main/java/com/hippo/scene/preference/PreferenceScene.java index e6f8b0471..43b3760d1 100644 --- a/app/src/main/java/com/hippo/scene/preference/PreferenceScene.java +++ b/app/src/main/java/com/hippo/scene/preference/PreferenceScene.java @@ -16,7 +16,6 @@ package com.hippo.scene.preference; -import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -45,8 +44,8 @@ public class PreferenceScene extends AppbarScene { private List mPreferenceBaseList = new ArrayList<>(); @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onCreate(boolean rebirth) { + super.onCreate(rebirth); setContentView(R.layout.scene_preference); mRecyclerView = (EasyRecyclerView) findViewById(R.id.recycler_view);