Cicerone
🚦 Cicerone is a lightweight library that makes the navigation in an Android app easy.
Install / Use
/learn @terrakok/CiceroneREADME
Cicerone
<table> <tr> <td> <img src="https://github.com/terrakok/Cicerone/raw/master/media/navigation.gif" width="256"/> </td> <td> <img src="https://github.com/terrakok/Cicerone/raw/master/media/insta_tabs.gif" width="256"/> </td> <td> <img src="https://github.com/terrakok/Cicerone/raw/master/media/animations.gif" width="256"/> </td> </tr> <tr> <td> Power navigation </td> <td> Multibackstack </td> <td> Result listeners </td> </tr> </table>Cicerone (a guide who gives information about antiquities and places of interest to sightseers) is a lightweight library that makes the navigation in an Android app easy.
It was designed to be used with the MVP/MVVM/MVI patterns but will work great with any architecture.
Main advantages
- Is not tied to Fragments
- Not a framework (very lightweight)
- Short navigation calls (no builders)
- Static typed checks for screen parameters!
- Lifecycle-safe!
- Functionality is simple to extend
- Suitable for Unit Testing
Additional features
- Opening several screens inside single call (for example: deeplink)
- Provides
FragmentFactoryif it needed addorreplacestrategy for opening next screen (seerouter.navigateTolast parameter)- Implementation of parallel navigation (Instagram like)
- Predefined navigator ready for Single-Activity apps
- Predefined navigator ready for setup transition animation
How to add Cicerone to your application
Add the dependency in your build.gradle:
dependencies {
//Cicerone
implementation("com.github.terrakok:cicerone:X.X.X")
}
Initialize the library (for example in your Application class):
class App : Application() {
private val cicerone = Cicerone.create()
val router get() = cicerone.router
val navigatorHolder get() = cicerone.getNavigatorHolder()
override fun onCreate() {
super.onCreate()
INSTANCE = this
}
companion object {
internal lateinit var INSTANCE: App
private set
}
}
How does it work?
<img src="https://github.com/terrakok/Cicerone/blob/master/media/CiceroneDiagram.png" alt="CiceroneDiagram.png" width="800"/>The Presenter calls the navigation method of Router.
class SamplePresenter(
private val router: Router
) : Presenter<SampleView>() {
fun onOpenNewScreen() {
router.navigateTo(SomeScreen())
}
fun onBackPressed() {
router.exit()
}
}
Router converts the navigation call to the set of commands and sends them to CommandBuffer.
CommandBuffer checks whether there are the _"active"_ Navigator:
- If yes, it passes the commands to the Navigator.
Navigatorwill process them to achive the desired transition. - If no, then
CommandBuffersaves the commands in a queue, and will apply them as soon as a new_"active"_ Navigatorwill appear.
fun executeCommands(commands: Array<out Command>) {
navigator?.applyCommands(commands) ?: pendingCommands.add(commands)
}
Navigator processes the navigation commands. Usually it is an anonymous class inside Activity.
Activity provides Navigator to the CommandBuffer in _onResume_ and removes it in _onPause_.
Attention: Use _onResumeFragments()_ with FragmentActivity (more info)
private val navigator = AppNavigator(this, R.id.container)
override fun onResumeFragments() {
super.onResumeFragments()
navigatorHolder.setNavigator(navigator)
}
override fun onPause() {
navigatorHolder.removeNavigator()
super.onPause()
}
Navigation commands
These commands will fulfill the needs of the most applications. But if you need something special - just add it!
- Forward - Opens new screen

- Back - Rolls back the last transition

- BackTo - Rolls back to the needed screen in the screens chain

- Replace - Replaces the current screen

Predefined navigator
The library provides predefined navigator for Fragments and Activity. To use, just provide it with the container and FragmentManager.
private val navigator = AppNavigator(this, R.id.container)
A custom navigator can be useful sometimes:
private val navigator = object : AppNavigator(this, R.id.container) {
override fun setupFragmentTransaction(
screen: FragmentScreen,
fragmentTransaction: FragmentTransaction,
currentFragment: Fragment?,
nextFragment: Fragment
) {
//setup your animation
}
override fun applyCommands(commands: Array<out Command>) {
hideKeyboard()
super.applyCommands(commands)
}
}
Screens
Describe your screens as you like e.g. create a Kotlin object with all application screens:
object Screens {
fun Main() = FragmentScreen { MainFragment() }
fun AddressSearch() = FragmentScreen { AddressSearchFragment() }
fun Profile(userId: Long) = FragmentScreen("Profile_$userId") { ProfileFragment(userId) }
fun Browser(url: String) = ActivityScreen { Intent(Intent.ACTION_VIEW, Uri.parse(url)) }
}
Additional you can use FragmentFactory for creating your screens:
fun SomeScreen() = FragmentScreen { factory: FragmentFactory -> ... }
Screen parameters and result listener
//you have to specify screen parameters via new FragmentScreen creation
fun SelectPhoto(resultKey: String) = FragmentScreen {
SelectPhotoFragment.getNewInstance(resultKey)
}
//listen result
fun onSelectPhotoClicked() {
router.setResultListener(RESULT_KEY) { data ->
view.showPhoto(data as Bitmap)
}
router.navigateTo(SelectPhoto(RESULT_KEY))
}
//send result
fun onPhotoClick(photo: Bitmap) {
router.sendResult(resultKey, photoRes)
router.exit()
}
Sample
To see how to add, initialize and use the library and predefined navigators see the sample project
(thank you @Javernaut for support new library version and migrate sample project to Kotlin!)
For more complex use case check out the GitFox (Android GitLab client)
Applications that use Cicerone
<a href="https://play.google.com/store/apps/details?id=ru.foodfox.client"><img src="https://play-lh.googleusercontent.com/gWYedIqy8QujCQOn0kzEIBEkGLBSpuKvFm-fMcfkWnJ1Oirtv847xAE4OyhAaohdcp5V=s360" width="64" /> Яндекс.Еда — доставка еды/продуктов. Food delivery</a><br> <a href="https://play.google.com/store/apps/details?id=com.kms.me"><img src="https://play-lh.googleusercontent.com/IBzu0tlHd_amw2HbjBLOZiCfK-0tn0CnwkMdOd1toP23rdHUV-i7L2ViNKgIg687=s360" width="64" /> Kaspersky Internet Security</a><br> <a href="https://play.google.com/store/apps/details?id=com.deliveryclub"><img src="https://play-lh.googleusercontent.com/m6-gFunvj7aQD5fdv8EdJZBN5M4REIobTaPZPYS0K5Td7CNYnazN7fOKiPwwaY3hJw=s360" width="64" /> Delivery Club – Доставка еды и продуктов</a><br> <a href="https://play.google.com/store/apps/details?id=ru.hh.android"><img src="https://play-lh.googleusercontent.com/YpAV7Q-ZJhI5tzFk_wEX-7-x2BydtnCtFTVUrmq0zAO6jLCLA4nNcfem3p_Pyowg9w=s360" width="64" /> Поиск работы на hh. Вакансии рядом с домом</a><br> <a href="https://play.google.com/store/apps/details?id=com.foodient.whisk"><img src="https://play-lh.googleusercontent.com/eKotZjJcZOU2_L9t2l34EEY7aGl5zhvKVuEbF0Kc4MRs_pAC2SJgOnWMkMTFjR_e9EY=s360" width="64" /> Whisk: Recipe Saver, Meal Planner & Grocery List</a><br> <a href="https://play.google.com/store/apps/details?id=kz.beeline.odp"><img src="https://play-lh.googleusercontent.com/hzgjpQQpy6Z-Byye0aVKSv9P7h8yx58i6pVkQtiM6jB99iWFXjYfKeaPqJ3wm6Rtb38=s360" width="64" /> Мой Beeline (Казахстан)</a><br> <a href="https://play.google.com/store/apps/details?id=com.mercuryo.app"><img src="https://play-lh.googleusercontent.com/FKulXdc15r5PWX6hTZi2i3iaJjcQHwd9xParp6YPiQ2KiBqza7jwEt_b_tqLwXpyEHg=s360" width="64" /> Mercuryo Bitcoin Cryptowallet</a><br> <a href="https://play.google.com/store/apps/details?id=com.warefly.checkscan"><img src="https://play-lh.googleusercontent.com/2c2uuiSl2vwGgp-vdI-VArQEMdSSXk1neUK5A-Udc0WANPcvp5kBJFEugrFiXnxUc7k=s360" width="64" /> ЧекСкан - кэшбэк за чеки, цены и акции в магазинах</a><br> <a href="https://github.com/eduard1abdulmanov123/News"><img src="https://raw.githubusercontent.com/eduard1abdulmanov123/News/dev/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png" width="64" /> RSS Reader для Вести.Ru</a><br> <a href="https://play.google.com/store/apps/details?id=com.epam.connect.android"><img src="https://play-lh.googleusercontent.com/aN7R6BiR7yt7b3oEoBI30pVwzsdzaWe3TWpw8c9igqoOj79Pm2xVh4_C4qwjSKwjVio=s360" width="64" /> EPAM Connect</a><br> <a href="https://play.google.com/store/apps/details?id=org.consumerreports.ratings"><img src="https://play-lh.googleuse
