Similarly to square/flow, Simple Stack allows you to represent your application state in a list of immutable data classes.
The library also allows easy backstack persisting through a delegate class, which handles configuration changes and process death.
If your data classes are not Parcelable
by default, then you can specify a custom parcellation strategy using setKeyParceler()
.
Additionally, the library also allows you to persist state of custom viewgroups that are associated with a given UI state into a StateBundle
.
This way, you can easily create a single-Activity application using either views, fragments, or whatevers.
The Backstack provides 3 convenient operators for manipulating state.
goTo()
: if state does not previously exist in the backstack, then adds it to the stack. Otherwise navigate back to given state.goBack()
: returns boolean if StateChange is in progress, or if there are more than 1 entries in history (and handled the back press). Otherwise, return false.setHistory()
: sets the state to the provided elements, with the direction that is specified.
The Backstack stores the screens.
The Backstack also allows navigation between the states (works as a router), and enables handling this state change using the StateChanger.
The library also provides two ways to handle both view-state persistence for views associated with a key, and persisting the keys across configuration change / process death.
-
The Navigator, which uses the BackstackHost retained fragment (API 11+) to automatically receive the lifecycle callbacks, and survive configuration change.
-
The BackstackDelegate, which works via manual Activity lifecycle callbacks - typically needed only for fragments.
Internally, both the the BackstackDelegate and the Navigator uses a BackstackManager, which can also be used.
The library provides a DefaultStateChanger, which by default uses Navigator to handle the persistence.
The keys used by a DefaultStateChanger must implement StateKey, which expects a layout key and a view change handler.
In order to use Simple Stack, you need to add jitpack to your project root gradle:
buildscript {
repositories {
// ...
maven { url "https://jitpack.io" }
}
// ...
}
allprojects {
repositories {
// ...
maven { url "https://jitpack.io" }
}
// ...
}
and add the compile dependency to your module level gradle.
compile 'com.github.Zhuinden:simple-stack:1.6.1'
The Backstack must be initialized with at least one initial state, and a StateChanger must be set when it is able to handle the state change.
The BackstackManager is provided to handle state persistence.
Convenience classes BackstackDelegate and Navigator are provided to help integration of the BackstackManager.
Setting a StateChanger begins an initialization
(in Flow terms, a bootstrap traversal), which provides a StateChange in form of {[], [{...}, {...}]}
(meaning the previous state is empty, the new state is the initial keys).
This allows you to initialize your views according to your current state.
Afterwards, the Backstack operators allow changing between states.
- Activity
public class MainActivity
extends AppCompatActivity {
public static final String TAG = "MainActivity";
@BindView(R.id.root)
RelativeLayout root;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
Navigator.install(this, root, HistoryBuilder.single(FirstKey.create()));
// additional configuration possible with `Navigator.configure()...install()`
}
@Override
public void onBackPressed() {
if(!Navigator.onBackPressed(this)) {
super.onBackPressed();
}
}
}
- StateKey
@AutoValue
public abstract class FirstKey
implements StateKey, Parcelable {
public static FirstKey create() {
return new AutoValue_FirstKey();
}
@Override
public int layout() {
return R.layout.path_first;
}
@Override
public ViewChangeHandler viewChangeHandler() {
return new SegueViewChangeHandler();
}
}
- Layout XML
<?xml version="1.0" encoding="utf-8"?>
<com.zhuinden.simplestackdemoexample.FirstView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<EditText
android:id="@+id/first_edittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Enter text here"/>
<Button
android:id="@+id/first_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go to second!"/>
</com.zhuinden.simplestackdemoexample.FirstView>
- Custom Viewgroup
public class FirstView
extends LinearLayout { // can implement Bundleable
public FirstView(Context context) {
super(context);
}
public FirstView(Context context, AttributeSet attrs) {
super(context, attrs);
}
//...
@OnClick(R.id.first_button)
public void firstButtonClick(View view) {
Navigator.getBackstack(view.getContext()).goTo(SecondKey.create());
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
ButterKnife.bind(this);
}
}
For more information, check the wiki page.
Copyright 2017 Gabor Varadi
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.