From aee4c4f0f4c644dd024cef2c5fa084af0684c1ac Mon Sep 17 00:00:00 2001 From: YuutaW <17158086+trumeet@users.noreply.github.com> Date: Sat, 13 Apr 2019 14:27:50 -0700 Subject: fix(app/library): add instance state handling Signed-off-by: YuutaW <17158086+Trumeet@users.noreply.github.com> --- app/src/main/java/moe/yuuta/flow/MainActivity.java | 33 +++++++++++- .../src/main/java/moe/yuuta/flow/FlowFragment.java | 63 +++++++++++++++------- .../src/main/java/moe/yuuta/flow/PageFragment.java | 15 +++--- .../java/moe/yuuta/flow/widgets/FlowPager.java | 4 +- 4 files changed, 84 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/moe/yuuta/flow/MainActivity.java b/app/src/main/java/moe/yuuta/flow/MainActivity.java index cba4bbd..d827aa6 100644 --- a/app/src/main/java/moe/yuuta/flow/MainActivity.java +++ b/app/src/main/java/moe/yuuta/flow/MainActivity.java @@ -6,6 +6,7 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import android.widget.TextView; import androidx.annotation.NonNull; @@ -26,9 +27,9 @@ public class MainActivity extends AppCompatActivity { super.onCreate(savedInstanceState); AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); Log.i(TAG, "onCreate()"); - if (mFragment == null) { + if (mFragment == null && savedInstanceState == null) { mFragment = new FlowFragment(); - mFragment.setPages(Arrays.asList(new Page1(), new Page2(), new Page3())); + mFragment.setPages(Arrays.asList(new Page1(), new Page2(), new Page3(), new Page4())); getSupportFragmentManager() .beginTransaction() .replace(android.R.id.content, mFragment) @@ -95,6 +96,34 @@ public class MainActivity extends AppCompatActivity { } } + public static class Page4 extends PageFragment { + public Page4() { + mInfo = new FlowInfo(new HeaderConfig("Page 4", "just a counter", false), null); + } + + // TODO: The FlowFragment keeps the instance, maybe we don't want that happened to child fragments. + private int mCount; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + Button button = new Button(requireContext()); + button.setMinHeight(20); + button.setText("+1s"); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mCount++; + HeaderConfig config = mInfo.getHeaderConfig(); + config.setSubtitleText(Integer.toString(mCount)); + mInfo.setHeaderConfig(config); + getHostFragment().notifyCurrentFlowInfoUpdated(); + } + }); + return button; + } + } + @Override public void onBackPressed() { if (mFragment != null && mFragment.onBackPressed()) return; diff --git a/library/src/main/java/moe/yuuta/flow/FlowFragment.java b/library/src/main/java/moe/yuuta/flow/FlowFragment.java index d7d4776..87deaf2 100644 --- a/library/src/main/java/moe/yuuta/flow/FlowFragment.java +++ b/library/src/main/java/moe/yuuta/flow/FlowFragment.java @@ -1,6 +1,7 @@ package moe.yuuta.flow; import android.os.Bundle; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -9,21 +10,25 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; +import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.ViewPager; import java.util.ArrayList; import java.util.List; /** - * The Host fragment + * The Host fragment. It is marked as final because it was set to remain instance. */ -public class FlowFragment extends Fragment implements IFlowFragment, View.OnClickListener { +public final class FlowFragment extends Fragment implements IFlowFragment, View.OnClickListener { + private static final String TAG = "FlowFragment"; + private List mPages = new ArrayList<>(0); // true: after the view settles, update the UI immediately. private volatile boolean mUIUpdateScheduled; + private static final String ARG_CURRENT = FlowFragment.class.getName() + ".ARG_CURRENT"; + private static final String ARG_UI_UPDATE_SCHEDULED = FlowFragment.class.getName() + ".ARG_UI_UPDATE_SCHEDULED"; + private Header mHeader; private ViewPager mPager; private NavigationBar mNav; @@ -73,18 +78,17 @@ public class FlowFragment extends Fragment implements IFlowFragment, View.OnClic } } - @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (getView() != null) return getView(); final View view = inflater.inflate(R.layout.fragment_flow, container, false); mHeader = new Header(view.findViewById(R.id.flow_host_header)); mNav = new NavigationBar(view.findViewById(R.id.flow_host_nav)); mPager = view.findViewById(R.id.flow_host_pager); - mPager.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) { + mPager.setAdapter(new FragmentStatePagerAdapter(getChildFragmentManager()) { @Override public Fragment getItem(int position) { - PageFragment fragment = mPages.get(position); - return fragment; + return mPages.get(position); } @Override @@ -93,13 +97,11 @@ public class FlowFragment extends Fragment implements IFlowFragment, View.OnClic } }); mPager.addOnPageChangeListener(mPageListener); - getChildFragmentManager().registerFragmentLifecycleCallbacks(mCallback, false); return view; } @Override public void onDestroyView() { - getChildFragmentManager().unregisterFragmentLifecycleCallbacks(mCallback); mPager.removeOnPageChangeListener(mPageListener); super.onDestroyView(); } @@ -107,6 +109,11 @@ public class FlowFragment extends Fragment implements IFlowFragment, View.OnClic @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + Log.d(TAG, "onViewCreated"); + if (savedInstanceState != null) { + Log.d(TAG, "onViewCreated - restore " + savedInstanceState.getInt(ARG_CURRENT, -1)); + mPager.setCurrentItem(savedInstanceState.getInt(ARG_CURRENT, 0)); + } if (mUIUpdateScheduled) { updateUI(); mUIUpdateScheduled = false; @@ -143,16 +150,6 @@ public class FlowFragment extends Fragment implements IFlowFragment, View.OnClic mPager.setCurrentItem(index, true); } - private FragmentManager.FragmentLifecycleCallbacks mCallback = new FragmentManager.FragmentLifecycleCallbacks() { - @Override - public void onFragmentPreCreated(@NonNull FragmentManager fm, @NonNull Fragment f, @Nullable Bundle savedInstanceState) { - if (f instanceof PageFragment) { - final PageFragment pf = (PageFragment) f; - pf.setHostFragment(FlowFragment.this); - } - } - }; - private ViewPager.OnPageChangeListener mPageListener = new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { @@ -191,4 +188,30 @@ public class FlowFragment extends Fragment implements IFlowFragment, View.OnClic public View.OnClickListener getGeneralFlowNavListener() { return this; } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // To save the child fragment instances + setRetainInstance(true); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + Log.d(TAG, "save"); + if (mPager != null) outState.putInt(ARG_CURRENT, mPager.getCurrentItem()); + if (mPager != null) Log.d(TAG, "current " + mPager.getCurrentItem()); + outState.putBoolean(ARG_UI_UPDATE_SCHEDULED, mUIUpdateScheduled); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + Log.d(TAG, "onActivityCreated"); + if (savedInstanceState != null) { + Log.d(TAG, "restore"); + mUIUpdateScheduled = savedInstanceState.getBoolean(ARG_UI_UPDATE_SCHEDULED, false); + } + } } diff --git a/library/src/main/java/moe/yuuta/flow/PageFragment.java b/library/src/main/java/moe/yuuta/flow/PageFragment.java index dcc9f21..4e7996b 100644 --- a/library/src/main/java/moe/yuuta/flow/PageFragment.java +++ b/library/src/main/java/moe/yuuta/flow/PageFragment.java @@ -1,24 +1,25 @@ package moe.yuuta.flow; +import android.util.Log; + import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; public abstract class PageFragment extends Fragment { - private IFlowFragment mHostFragment; - /** * Once mInfo is changed, you should call {@link IFlowFragment#notifyCurrentFlowInfoUpdated()} to publish it. * Note: it will be permanently change the recorded info. */ protected FlowInfo mInfo; - final void setHostFragment(@NonNull IFlowFragment hostFragment) { - this.mHostFragment = hostFragment; - } - @NonNull protected final IFlowFragment getHostFragment() { - return mHostFragment; + final Fragment parent = getParentFragment(); + if (!(parent instanceof IFlowFragment)) { + throw new IllegalStateException("This fragment is not attached to a valid flow host"); + } + Log.d("Page", "get"); + return (IFlowFragment) parent; } /** diff --git a/library/src/main/java/moe/yuuta/flow/widgets/FlowPager.java b/library/src/main/java/moe/yuuta/flow/widgets/FlowPager.java index c821eef..e76f319 100644 --- a/library/src/main/java/moe/yuuta/flow/widgets/FlowPager.java +++ b/library/src/main/java/moe/yuuta/flow/widgets/FlowPager.java @@ -8,7 +8,7 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentPagerAdapter; +import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.ViewPager; public class FlowPager extends ViewPager { @@ -27,7 +27,7 @@ public class FlowPager extends ViewPager { if(null != getAdapter()) { int height = 0; - View child = ((FragmentPagerAdapter) getAdapter()).getItem(getCurrentItem()).getView(); + View child = ((FragmentStatePagerAdapter) getAdapter()).getItem(getCurrentItem()).getView(); if (child != null) { child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); height = child.getMeasuredHeight(); -- cgit v1.2.3