Giter VIP home page Giter VIP logo

Comments (6)

Zhuinden avatar Zhuinden commented on May 23, 2024 1

There are multiple ways to go about it, but you are right, I should add an example for this.

The two ways I can think of:

The root view (which is bound to the key that is the top new state) manages the existence of the nested views that can exist inside it by inflating them with LayoutInflater.from(new KeyContextWrapper(getContext(), nestedKey)).inflate(R.layout.nested_view, this, false); in order for them to have their own key.

There are two ways that state persistence can be handled.

1.) the root view manages the state of its children through collecting them into the bundle provided by Bundleable, and they are restored from that bundle.

2.) each child is able to write into BackstackDelegate.persistViewToState(this);, but by default behavior BackstackDelegate.clearStatesNotIn() clears all keys that are not in the new state of the backstack (stateChange.getNewState()), therefore to preserve children of a composite key, one must be able to obtain what keys exist on top of what is inside the backstack itself; and redefine backstackDelegate.clearStatesNotIn() to keep those states as well.


Previously I've been using approach 1 (which takes a bit of boilerplate but it works), but I'm also working on making it possible with approach 2 without having to explicitly redefine clearStatesNotIn() as user of the library.


Child keys and Composite keys are on the roadmap; I'm in the process of figuring them out ( see here where I'm experimenting with the how).


In the meantime, I can show you a pager adapter for ViewPager that can store the state of its children:

public abstract class ViewPagerAdapter
        extends PagerAdapter {
    final Bundle[] bundles = new Bundle[getCount()]; 
    final View[] views = new View[getCount()];

    @Override
    public View instantiateItem(ViewGroup container, int position) {
        View view = getItem(position);
        if(bundles[position] != null) {
            Bundle savedState = bundles[position];
            view.restoreHierarchyState(savedState.getSparseParcelableArray("viewState"));
            if(view instanceof Bundleable) {
                ((Bundleable) view).fromBundle(savedState.getBundle("bundle"));
            }
        }
        container.addView(view);
        views[position] = view;
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        View view = (View)object;
        if(bundles[position] == null) {
            bundles[position] = new Bundle();
        }
        Bundle savedState = bundles[position];
        saveStateForView(view, savedState);
        views[position] = null;
        container.removeView(view);
    }

    @Override
    public Parcelable saveState() {
        Bundle pagerState = new Bundle();
        for(int i = 0; i < getCount(); i++) {
            if(views[i] != null) {
                if(bundles[i] == null) {
                    bundles[i] = new Bundle();
                }
                View view = views[i];
                Bundle savedState = bundles[i];
                saveStateForView(view, savedState);
            }
            if(bundles[i] != null) {
                Bundle viewState = bundles[i];
                pagerState.putBundle("viewState_" + i, viewState);
            }
        }
        return pagerState;
    }

    private void saveStateForView(View view, Bundle savedState) {
        SparseArray<Parcelable> viewState = new SparseArray<>();
        view.saveHierarchyState(viewState);
        savedState.putSparseParcelableArray("viewState", viewState);
        if(view instanceof Bundleable) {
            savedState.putBundle("bundle", ((Bundleable) view).toBundle());
        }
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
        Bundle pagerState = (Bundle)state;
        pagerState.setClassLoader(loader); // added to fix BadParcelException on process death
        for(int i = 0; i < getCount(); i++) {
            Bundle viewState = pagerState.getBundle("viewState_" + i);
            if(viewState != null) {
                bundles[i] = viewState;
            }
        }
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    public abstract View getItem(int position);
}

Now if clearStatesNotIn() is overridden, then the Bundle and SparseArray you see here can be replaced with backtackDelegate.getSavedState(key), if getItem() returns a view that is associated with its own key.

Otherwise, PagerState preserves it into root key's SavedState.



With current default setup, you can use Bundleable to save state into parent view's bundle. That's what I've been doing.

from simple-stack.

Zhuinden avatar Zhuinden commented on May 23, 2024 1

@blackkara the latest update v1.1.1 also includes simple-stack-example-multistack which shows how to use Simple-Stack with multiple backstack per each tab on a bottom nav view in one activity.

from simple-stack.

Zhuinden avatar Zhuinden commented on May 23, 2024

I will close this for now, I've answered the question: the parent must handle the state management of their children. Whether you use a Backstack instance and register the custom view as a StateChanger is up to you.

This is improved upon when composite keys are introduced, tracked in #12.

Another similar use-case will be covered by #13.

from simple-stack.

blackkara avatar blackkara commented on May 23, 2024

Firstly thanks and then sorry for my lated reaction. Your comments (pager adapter way) and multistack example work like a charm ! I implemented them on different sample projects individually to get idea and difference.

Actually i had tried the pager adapter way before the latest multistack example already. So,

  • Activity layout contains only RelativeLayout (root)
  • Created custom view (say SkeletonView) that includes bottom navigation.
  • Created other custom views (say AView, BView, CView) for bottom navigation in SkeletonView
  • Inflated SkeletonView and added to root (And inflated A,B,C views)
  • And then created a new custom view to replace with SkeletonView.

You can think the last step like, i wanna go to a screen that doesn't have bottom navigation (maybe about page) So i did all of them with help of your first comment.

But, multistack example doesn't allow this navigation technically, Because activity layout has already structure including bottom navigation. And the root view in it, services for only tabs. Now i'm converting the multistack example for my scenario

from simple-stack.

Zhuinden avatar Zhuinden commented on May 23, 2024

@blackkara actually, your concern is legitimate - if you separate the bottom navigation into 4 different stacks, then you pretty much can't swap out the "main view" as a viewgroup, because the scope of the bottom navigation becomes bound to the Activity instance.

So the multi-stack example is more-so for when you have to keep 4 separate tabs up and can navigate between them at any time.


I can barely wait to finish 2.0 which will bring Composite Keys and a local backstack for each view associated with a key.

from simple-stack.

Zhuinden avatar Zhuinden commented on May 23, 2024

Along with the view-pager example shown above, another possibility is to use service-tree to provide managed services for the given keys (so that they survive configuration change and depend on the simple-stack history instead), allowing BackstackManager to be created and used per view.

Now with 1.3.0, an example called simple-stack-example-nestedstack is added for a setup for this particular type of complex nesting.

from simple-stack.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.