Folio is a Page based navigation framework for Android with a simplified lifecycle and easy transition animations. It's intended to fulfil a similar role to fragments while looking more like Activities.
Apps using Folio in production
Folio follows Semantic Versioning.
Folio is available on jcenter.
compile 'com.umaplay.oss:folio:1.0.0'
Download the aar artifact from the artifacts directory and copy it into the libs directory of your app module.
Specify libs
as a repository in your root gradle file.
allprojects {
repositories {
...
flatDir { dirs 'libs' }
}
}
Specify Fluxxan as dependency in your app's gradle file.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile(name: 'folio-1.0.0', ext: 'aar')
...
}
A Folio app is composed of simple Pages. If you are familiar with Activities, then you'll be right at home using Folio. The lifecycle is simple and similar to that of Activities.
Folio is composed of the
- Host
- PageManager
- Page
- PageFactory
Pages are hosted inside of an Activity
, Fragment
or even another Page
.
A PageManager
handles the lifecycle of the pages and ensures everything remains consistent.
The Host is responsible for notifying the PageManager
of lifecycle changes and also, can respond to changes in the Stack.
The Host can be an Activity
, Fragment
or even another Page
. The Host must call the respective lifecycle methods on PageManager
.
PageManager.onStart
PageManager.onResume
PageManager.onPause
PageManager.onStop
PageManager.onDestroy
PageManager.onSaveInstanceState
Folio provides a PagedActivity
which handles the heavy lifting of notifying the PageManager
of lifecycle changes, handling on Activity.onBackPressed
and responding when the Stack is empty.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//create and set our manager which we can retrieve later using getPageManager()
setPageManager(new PageManager((ViewGroup) findViewById(R.id.container), this, App.getRefWatcher(), savedInstanceState));
//if instance state is null, then this is our first launch, let's navigate to the main page
//the page manager automatically restores the stack from the savedInstanceState
if (savedInstanceState == null) {
getPageManager().goTo(new RedPage.RedPageFactory());
}
}
The PageManager
manages all pages. A Host can have as many instances as is feasible and Each Page can have a NestedPageManager
for free (the library handles it's lifecycle for you).
Each manager requires a container which is simply a ViewGroup
(FrameLayout
works great), a PageStackDelegate
which is notified when the stack is empty and importantly, an instance of com.squareup.leakcanary.RefWatcher
to help catch memory leaks.
We enforce the use of the RefManager because a memory leak can bring the entire application to it's knees very quickly.
When navigating to a page, you can provide a PageAnimatorFactory
which animates the addition and removal of Pages. By default, Pages are not animated.
Folio includes AnimatorUtils
which can help you create simple translation and fade animators. But you are free to create your own.
You can add StackChangedListener
s to listen to changes in the stack and react accordingly. For example, to update an actionbar (if you choose to manage it in the host).
A Page is a self contained "screen" in a Folio application with a simple lifecyle and state preservation. Pages are modelled after activities and therefore easy to use.
The lifecycle is simple and easy to understand. It's been detailed in the diagram below. Click to view large size.
You can get a context instance by calling getContext()
between onViewMounted
and onViewUnmounted
. Doing so outside of this will throw an IllegalStateException
.
A Page can get a cheap PageManager by calling getNestedPageManager(ViewGroup)
.
The NestedPageManager
is considered cheap because it is handled by the framework internally and you don't have to worry about the lifecycle or state handling.
This makes creating a Master/Detail view very easy to implement.
Because the Page lifecycle is independent of the Host's, using the context for libraries that rely on the Lifecycle to clean up resources can lead to increased memory usage e.g. Glide. You wil need to find a way to bypass it. Refer to this gist for an implementation that supports Glide.
PageFactory
handles the creation of Pages and storing of some information related to the Page. The provided BasePageFactory
provide an implementation that handles all the heavy lifting.
The PageFactory
and PageAnimatorFactory
must be serializable.
- Ensure that any properties are serializable.
- If nested, make sure it is a static class.
- Do not use an anonymous class
If the Factory cannot be serialized, the app will crash.
Thank you for taking the time to contribute. But before you do, please read our contribution guidelines. They are simple, we promise.
- Writing Tests
MIT