Forget about Fragments with FlairFramework (part 1)

Alexandr Minkin
4 min readAug 5, 2018

Hello everybody. In this article i’m going to talk about Android development without Fragments and Activities. I was worked with Fragments for 2 years and I always felt pain when I used them. Then I learned about the existence of a framework that does not use fragments, it’s called Conductor that was writen on Java. As i really love to develop Android applications with Kotlin, i start to search something looks similar to Conductor, but i didn’t find any results. After this, i was started to develop my own realisation of framework that does’t use a Fragments and was writen on clean Kotlin language. I was so inspired of Bluelinelabs work and my own last two frameworks (ViamFramework & KotlinMVC). And now, after spended a lot of time for hard work to complete this task, i want to represent to the community such a perfect result called FlairFramework. It’s create on top of MVC pattern with powerful event system (Observer Pattern), dependency injection and property delegation, also it support multi-core instances (Facade Pattern), backstack store for navigation and animation changes between views.

The main components of this framework is:

  1. ‘flair’ instance is a simple IFacade singleton instance as core functionality point
  2. SimpleCommand instances is a command pattern realisation. You can manipulate proxy objects from it’s instance as like UseCases
  3. MacroCommands can combine more than one SimpleCommand and execute it one by one
  4. Proxy objects is a complex object that store data to manipulate with, it’s like repository for ur network calls or database, also it can be a Presenters for your Mediators.
  5. Mediator is a simple view-hierarchy handler class, it’s store and manage lifecycle of your view components such as AnkoComponents or xml-layout files. Mediators combines together with IView interface implementation as a part of MVC pattern that support view backstack storage for navigation.
  6. Also you has LinearAnimator.kt for create simple view animation changes such as horizontal animation, or u can implement IAnimator.kt and create your own animation changes.
  7. All components of a FlairFramework are linked together by a powerful messaging system (thanks to Observer Pattern). You can notify every part of your system by calling sendNotification(event, data) and subscribe on event by calling registerObserver(event) { INotification -> } in IMediator or execute another SimpleCommand (see example above). Mediator can notify commands, commands can notify mediators and another commands, proxy can notify mediators and another commands.

The start point for initialize framework is declare ‘flair’ instance in onCreate method in MainApplication.kt file or by the reference. But u can initialize framework in any part of your project such as MainActivity(you must extendFlairActivity ) or any Context implementations. See how it simple:

class FlairApplication : Application() {
/// That's how u register your "flair" components
private val flairFirstCore = flair {
registerCommand<StartupCommand>(STARTUP)
registerCommand<UserAuthCommand>(AUTH)
registerCommand<AccountCommand>(ACCOUNT_CHANGE)
registerCommand<AccountCommand>(ACCOUNT_CLEAR)
registerCommand<LogicMacroCommand>(LOGIC_START)
}

override fun onCreate() {
super.onCreate()
/*
// alternative way to register components
flair {
registerCommand<StartupCommand>(STARTUP)
registerCommand<UserAuthCommand>(AUTH)
registerCommand<AccountCommand>(ACCOUNT_CHANGE)
registerCommand<AccountCommand>(ACCOUNT_CLEAR)
registerCommand<LogicMacroCommand>(LOGIC_START)
}*/
}
}

The second part or using ‘Flair’ is attach created core to single Activity class and root layout container (but u can no specify any root container and flair take it for you automatically as activity.window.decorView.findViewById(android.R.id.content)). Important thing: only one activity (that should be an instance of FlairActivity) can be stored in one core of FlairFramework.

There is an example:

class MainActivity : FlairActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val showingAnimation = LinearAnimator()
flair().attach(this).showLastOrExistMediator<MyMediator>(showingAnimation)
// or with Anko
// val rootContainer = frameLayout()
// flair().attach(this, rootContainer).retrieveMediator<MyMediator>().show()
}
}

And Simple MyMediator.kt example is light-weight component that has only useful lifecyrcle methods such as :
- onPrepareCreateView() // called when view is ready to be created
- onCreatedView(view: View) // called when view is created but not added to container
- onAddedView(view: View) // viewComponent is added to root container
- onRemovedView(view: View) // viewComponent is removed from root container
- onDestroyView() // called when view is cleared and destroyed

class MyMediator : Mediator() {    // called when medaitor is registered
override fun onRegister() {
// register notification for this IMediator instance
registerObserver(eventName:String) { notification ->
// event handler
}
sendNotification(eventName)
}
// the way to create UI
override fun createLayout(context: Context): View = UserAuthUI().createView(AnkoContext.create(context, this))
// or you can inflate you custom xml layout
// override fun createLayout(context: Context): View = inflateView(R.layout.simple_layout)

inner class UserAuthUI : AnkoComponent<MyMediator> {
override fun createView(ui: AnkoContext<MyMediator>) = with(ui) {
verticalLayout {
lparams(matchParent, matchParent)
textView("HELLO WORLD")
}
}
}
}

From every Mediator instance you can call
- showMediator<T:IMediator>(mediatorName:String?) — to show another IMediator implementation , and if it’s not registered before, don’t worry, it will be registered if it doesn’t exist in mediator store.
- popToBack() — it will goes back to previous mediator if it has and clear current mediator from backstack
- popTo<T:IMediator>(mediatorName:String?) — pop current mediator from backstack to given generic mediator or by it’s name.
- hide() — remove current mediator from root container

Simple right?!

This is a first part of using this powerful framework, where I tried to show you how easily you can build an independent ui with FlairFramework and the mediators. In the second part i will explain to you how to use Proxy objects and combine it with Commands. See my githab page with more complex examples. Thanks for reading this article. See you soon!

links: https://github.com/Rasalexman/Flair

P.s.: I really want to get a feedback from developers to help me improve this project. I spend many times to make it better. So if you have any question or find some bugs please let me know about this to create an issue on github or write an email.

--

--

Alexandr Minkin

Lead Software Developer. Kotlin enthusiast, Android developer, Swift lover, Clean Architecture Supporter