Taming the Android lifecycle
Android components are mainly managed by their lifecycle: we can't directly instantiate an Activity nor a Fragment. The system make all creation and management for us, and make callbacks on methods: onCreate, onStart...
That's why we can't describe our Activity/Fragment/Service in a Koin module. We need then to inject dependencies into properties and also respect the lifecycle: Components related to the UI parts must be released on soon as we don't need them anymore.
Then we have:
- long live components (Services, Data Repository ...) - used by several screens, never dropped
- medium live components (user sessions ...) - used by several screens, must be dropped after an amount of time
- short live components (views) - used by only one screen & must be dropped at the end of the screen
Long live components can be easily described as
single definitions. For medium and short live components we can have several approaches.
In the case of MVP architecture style, the
Presenter is a short live component to help/support the UI. The presenter must be created each time the screen is showing,
and dropped once the screen is gone.
A new Presenter is created each time
We can describe it in a module:
factory- to produce a new instance each time the
scope- to produce an instance tied to a scope
Most of Android memory leaks come from referencing a UI/Android component from a non Android component. The system keeps a reference on it and can't totally drop it via garbage collection.
Scope for Android Components
Declare a scope
To use a scoped Android component, you have to declare a scope for your component with the
scope block like follow:
Use an Android scope
FragmentScope classes, to let you use directly a declared scope for Activity or Fragment:
If you can't use such classes, we need to use the
AndroidScopeComponent interface and implement the
scope property. This will setup the default scope used by your class.
scope property can be used with the following property delegates, regarding your component:
activityScope()- Follow Activity lifecycle
activityRetainedScope()- Follow Activity's ViewModel lifecycle
fragmentScope()- Follow Fragment lifecycle, and is linked to parent's scope
serviceScope()- Follow Service lifecycle
ActivityScope class will use a
FragmentScope class will use
fragmentScope() by default.
We can also setup a scope, tied to a ViewModel with the following:
Sharing instances between components with custom scopes & Scope Links
In a more extended usage, you can use a
Scope instance across components. For example, if we need to share a
First declare a scope definition:
When needed to begin use a
UserSession instance, create a scope for it:
Then use it anywhere you need it: