Stasis is a general purpose library to persist state using annotation processing and code generation.
Android user interface classes (Activity
s, Fragment
s, etc) provide a (limited) mechanism to save important bits of the UI state (the onSavedInstanceState(Bundle)
and onRestoreInstanceState(Bundle)
mechanism).
However, in practice this is not comprehensive enough to fully restore the UI.
There's flags that aren't commonly known by developers (like freezesText
for TextView
s), data that can't normally be accessed, or other things that can't be stored properly in a Bundle
(like adapters, etc).
Stasis provides an Android specialisation with sensible defaults for UI state preservation.
Stasis uses a similar approach to Jake Wharton's ButterKnife library.
In a class you'd like to preserve, just annotate the relevant fields with the @Preserve
annotation and the annotation processor generates a PreservationStrategy
for your class.
In your modules build.gradle
dependencies, add:
compile "com.tierable.stasis:stasis-lib:$stasisVersion"
// For Android projects
compile "com.tierable.stasis:stasis-lib-android:$stasisVersion"
To enable annotation processing:
For Android:
annotationProcessor "com.tierable.stasis:stasis-compiler:$stasisVersion"
For Java
apt "com.tierable.stasis:stasis-compiler:$stasisVersion"
For Kotlin?
kapt "com.tierable.stasis:stasis-compiler:$stasisVersion"
Provide a single interface (for now?) in your module and mark it with the @PreservationMapping
annotation.
You can define a fallback strategy if you don't want to define a mapping for every type of preserved class.
The default fallback strategy is to not save anything.
The mapping interface can extend other interfaces. Methods in the interface:
- Can be named whatever you desire (as long as it makes sense).
The
getStrategy
name has been used in examples as an appropriate name though - Must return a
PreservationStrategy
- Can have more than one parameter if you need the same
PreservationStrategy
for multiple types
// Uses the marker annotation
@PreservationMapping(MyFallbackPreservationStrategy.class)
public interface DemoMapping
extends AnotherMapping, YetAnotherMapping {
// Multiple mappings for a PreservationStrategy
PreservationStrategyButton getStrategy(Button button, ButtonChildClass buttonChildClass);
// Single mapping for a PreservationStrategy
PreservationStrategyTextField getStrategy(TextField textField);
// etc
}
Just create a class implementing the PreservationStrategy
interface or extending a pre-existing PreservationStrategy
.
The only limitation is that you can only use the default (no argument) constructor for generated code.
Stasis generates a PreservationStrategy
implementation for every class with atleast one member annotated with @Preserve
.
The generated class names will be in the format PreservationStrategy[YourClassNameHere]
and will be outputted to the same package.
Preserved fields must be either public or package private so they are accessible by the generated code.
public class DemoClass {
@Preserve
Button buttonWithADefaultPreservationStrategy;
@Preserve(value = MyCustomButtonPreservationStrategy.class)
Button buttonWithACustomPreservationStrategy;
@Preserve(enabled = false)
Button buttonWithPreservationDisabled;
Button buttonNotPreserved;
// Generated by Stasis
private PreservationStrategyDemoClass preservationStrategy;
public void initialise() {
preservationStrategy = new PreservationStrategyDemoClass();
}
public void saveState() {
// 'Freeze'/'save' this classes state
preservationStrategy.freeze(this);
// TODO: save the preservationStrategy somewhere
}
public void restoreState() {
// TODO: Restore the preservationStrategy from somewhere
// 'UnFreeze'/'restore' this classes state
preservationStrategy.unFreeze(this);
}
// etc
}