Releases: rainbowcake/rainbowcake
0.4.3
Eleventh release of RainbowCake.
What's new:
The contentFrame
ID that's used in the activity_main
layout is now declared in a separate XML file to avoid crashes produced by it not being present if the layout is overridden.
0.4.2
Tenth release of RainbowCake.
What's new:
Not much!
Updates of various dependencies
- Dagger 2.24 (incremental by default!)
- Kotlin 1.3.50
- Coroutines 1.3.0
- Gradle 5.6
- Android Gradle plugin 3.5.0
Navigator documentation updates
The pop
and popUntil
methods now have documented return values.
0.4.1
Ninth release of RainbowCake.
What's new:
ViewState handling fixes
Version 0.4.0 caused some unexpected behaviour when reading the viewState
immediately after setting it to a new value, as continuously blocking the thread between these two operations didn't allow the set operation to complete, therefore the read showed an outdated state. This should be fixed now.
The postState
method is now even more deprecated than before. You should really only update state via viewState
and from the UI thread. Please.
0.4.0
Eight release of RainbowCake.
What's new:
Dagger artifact
Dagger related code has been moved to a separate artifact, which you can include the following way:
implementation "co.zsmb:rainbow-cake-dagger:$rainbow_cake_version"
Some imports have also been changed to reflect this. Here's a quick table of what you'll need to migrate (should be just a quick search & replace, so no script this time):
Original | Replacement |
---|---|
co.zsmb.rainbowcake.di.RainbowCakeComponent |
co.zsmb.rainbowcake.dagger.RainbowCakeComponent |
co.zsmb.rainbowcake.di.RainbowCakeModule |
co.zsmb.rainbowcake.dagger.RainbowCakeModule |
co.zsmb.rainbowcake.di.ViewModelKey |
co.zsmb.rainbowcake.dagger.ViewModelKey |
co.zsmb.rainbowcake.RainbowCakeApplication |
co.zsmb.rainbowcake.dagger.RainbowCakeApplication |
co.zsmb.rainbowcake.base.getViewModelFromFactory |
co.zsmb.rainbowcake.dagger.getViewModelFromFactory |
Koin support
Why mess around with all that Dagger stuff? Because it's no longer the only game in town. You may now also use Koin 2.0 for your dependency injection needs with RainbowCake.
-
Include the new Koin artifact:
implementation "co.zsmb:rainbow-cake-koin:$rainbow_cake_version"
-
Replace Dagger with Koin in your dependencies, here are some recommended artifacts:
def koin_version = '2.0.1' implementation "org.koin:koin-core:$koin_version" implementation "org.koin:koin-android:$koin_version" implementation "org.koin:koin-android-viewmodel:$koin_version"
-
Set up Koin. You won't need
@Inject
annotations any more, but you'll have to declare modules and start up your Koin (ideally, in yourApplication
'sonCreate
method). See the getting started guide for more details.
Note: You may also use the two DI solutions within the same RainbowCake project simultaneously, for example if you're migrating a project piece by piece. Even shared ViewModels should work!
Proper license
The project is now licensed under Apache 2. One more step towards proper open source.
Android Studio template updates
The screen template now has an option to generate new screens that are powered by Koin, and both the screen and ListAdapter templates now support AndroidX!
0.3.0
Seventh release of RainbowCake.
What's new:
Channels artifact
Channel related code has now been moved from the core library to the rainbow-cake-channels
artifact. It also includes a new feature, converting a LiveData
instance to a Channel
:
fun getNews(): ReceiveChannel<List<News>> {
return newsDao.getNews().toChannel()
}
This, as with other Channel related API, is experimental (but seems to work alright).
Changes:
Navigation extension reorganization
Argument handling extensions have been moved from the core library to the navigation artifact. Their package names have also been changed to reflect this change. The old extensions are now deprecated.
Documentation
The previously used documentation repo is now deprecated. See rainbowcake.dev instead.
Version updates:
- Coroutines 1.2.0
0.2.0 - The Breaking Changes Release
Preface
This release contains many structural changes, and some new features. However, it contains no critical bugfixes. This means that if you don't want to suffer the cost of updating to this version right now, the previous version should keep working for you just fine.
If you keep using the old version and do find critical issues in it, report the issue, and a bugfix release using the old structure and package names will be provided for you, if necessary.
Update steps
Updating your project is going to be just a little bit more effort than usual (should still be about 2 minutes using Studio, really).
-
Update your Gradle dependencies (as necessary, see the Repackaging section):
def rainbow_cake_version = '0.2.0' implementation "co.zsmb:rainbow-cake-core:$rainbow_cake_version" implementation "co.zsmb:rainbow-cake-navigation:$rainbow_cake_version" implementation "co.zsmb:rainbow-cake-timber:$rainbow_cake_version"
-
Perform the following search and replace actions in your project - Ctrl + Shift + R:
Original Replacement hu.autsoft.rainbowcake
co.zsmb.rainbowcake
BaseViewModel
RainbowCakeViewModel
BaseFragment
RainbowCakeFragment
BaseActivity
RainbowCakeActivity
BaseApplication
RainbowCakeApplication
BaseModule
RainbowCakeModule
BaseComponent
RainbowCakeComponent
There is also a migration script available to perform this search and replace task. This script does its best to safely migrate your project, but be sure to check the changes it makes.
The script can be invoked in the following way:
./rc-migration.sh ~/projects/MyProject
Or for example, on Windows, from a Git bash:
./rc-migration.sh /c/projects/MyProject
-
Add configuration to your project as necessary (see the New configuration options section for details).
Note that previous versions of the library logged internal events to Timber by default, while the new configuration feature disables internal logging by default. This means you won't see stacktraces of uncaught
Exception
s caught byJobViewModel
anymore. If you wish to re-enable previous behaviour, set the following configuration options (again, details explained below):rainbowCake { isDebug = BuildConfig.DEBUG logger = Loggers.TIMBER }
-
Update your Android Studio templates (should be just a simple
git pull
).
Read on to see the explanation of why all these steps are required.
Huge changes
Repackaging
The package names of the framework, as well as the artifact group IDs have been changed from hu.autsoft
to co.zsmb
.
The framework is also no longer being published as a -SNAPSHOT
. These are now regular, stable releases (albeit non-final, because nothing ever is).
As a modularization effort, the framework is being split up into multiple artifacts - only three, for now. This means including three separate Gradle dependencies in your project, if you actually need the features from all of them.
The currently available artifacts are:
Core
implementation "co.zsmb:rainbow-cake-core:0.2.0"
Contains everything from previous versions, except for the navigation features.
Navigation addon
implementation "co.zsmb:rainbow-cake-navigation:0.2.0"
Contains all the navigation features that were part of the base artifact before.
Timber addon
implementation "co.zsmb:rainbow-cake-timber:0.2.0"
You only need this artifact if you want the framework to log about its internal events (this is mostly just the exceptions caught by JobViewModel
), and you want it to do so using Timber. See details below.
Base classes renamed
The base classes BaseViewModel
, BaseFragment
, and BaseActivity
have been renamed to RainbowCakeViewModel
, RainbowCakeFragment
, and RainbowCakeActivity
, respectively.
This change makes the Base*
names available for applications using the framework, so that they may create their own Base*
classes that inherit from the framework classes, and include any app-specific extra behaviour there.
New configuration options
The framework now has a configuration DSL, which can be invoked in the onCreate
method of your Application
class.
Its usage looks like the following:
override fun onCreate() {
super.onCreate()
rainbowCake {
isDebug = false
logger = Loggers.NONE
consumeExecuteExceptions = true
}
}
The available settings, and their possible values:
isDebug
: Boolean,false
by default.- If set to false, it disables all internal logging of the framework, regardless of the setting of
logger
. May affect other behaviour in the future as well (in debug mode, prod behaviour will definitely not change). Recommended value isBuildConfig.DEBUG
.
- If set to false, it disables all internal logging of the framework, regardless of the setting of
consumeExecuteExceptions
: Boolean,true
by default (to keep existing behaviour).- Determines whether the
execute
method inJobViewModel
should catch and log any uncaught exceptions in coroutines, or let them crash the app. Recommended to be set tofalse
at the very least for debug builds, and should be considered even for production.
- Determines whether the
logger
- Determines how the framework should log its internal events. Available options by default are
NONE
(as in no logging) andANDROID
(logs to Logcat viaLog.d
). - If the
rainbowcake-timber
dependency is included,TIMBER
may also be used to log via Timber. Note that this doesn'tplant
anyTree
s, you still have to do that yourself.
- Determines how the framework should log its internal events. Available options by default are
Events rework
Event handling has been significantly reworked under the hood, since they were quite broken in some edge cases.
- When using shared
ViewModel
instances with scopes, only a single one of the attachedFragment
would receive the events, chosen randomly. - If a
Fragment
was inactive (in the background) while itsViewModel
posted events, only the last event posted would be delivered when it became active again, due to the nature ofLiveData
.
For the first issue: the new events mechanism ensures that all attached Fragment
s receive each event, so that they may each react to it as appropriate.
As for the second problem, you may now decide whether an event only makes sense for the Fragment
to receive immediately (most events will fall in this category!), or if they should be remembered if the Fragment
is not currently active, and delivered later.
Both of these types of events will still be received in the onEvent
method of your RainbowCakeFragment
or RainbowCakeActivity
, but you have to send them in different ways.
Active observer only events
Events that should only be delivered immediately should still implement the OneShotEvent
marker interface, and be sent using postEvent
, just like before. (One small caveat: this method can now only be called from the UI thread, which you should already have been doing anyway.) If you send one of these events when the Fragment
is not active, it will never be delivered.
99% of the time, this is the behaviour you need for your events, and the type of events you should use.
Queued events
Events that matter even if they can't be delivered immediately have to implement the QueuedOneShotEvent
marker, and be sent using postQueuedEvent
. If the observing Fragment
isn't currently active, the event will be queued, and all queued events will be delivered immediately when the Fragment
becomes active again.
Each Fragment
instance has its own independent queue of events. Note that Fragment
s in the background can be destroyed and recreated by the framework, and their queues will be lost in this case - this is a best effort mechanism.
Events wrapup
If all of this looks confusing at first, the good news is that you probably don't need all this! You can just keep using events like before, and they'll keep working. They're just much more reliable now.
MultiDex removed
The framework used to include the multidex support dependency and initialize MultiDex in BaseApplication
by default. Forcing this on applications in this form was a mistake (most notably since apps targeting API 21+ don't need these to use multidex) and has now been removed.
Any apps targeting API levels below 21 should now perform these steps for themselves, if they require multidex.
Small changes
Slicker popUntil
The popUntil
navigation method can now be used with a reified type parameter instead of a KClass
parameter. So instead of navigator?.popUntil(HomeFragment::class)
, you can now navigator?.popUntil<HomeFragment>()
!
ViewModel scoping improvements
...
0.1.2-SNAPSHOT
Fifth snapshot release of RainbowCake.
What's new:
New Navigator method to execute pending actions together
Previously, sequences of Navigator
method calls have always executed individually, e.g. take this call:
navigator?.run {
popUntil(HomeFragment::class)
add(SomeFragment())
}
Here, the current Fragments on top of HomeFragment
would have first been removed, HomeFragment
appeared for a split second, and then SomeFragment
would be added on top.
You can now prevent this "flashing" behaviour by calling navigator.executePending()
after a series of actions, like so:
navigator?.run {
popUntil(HomeFragment::class)
add(SomeFragment())
executePending()
}
Version updates:
- Kotlin 1.3.21
- Android Gradle plugin 3.3.1
0.1.1-SNAPSHOT
Fourth snapshot release of RainbowCake.
Update steps:
Update your dependency version:
implementation 'hu.autsoft:rainbow-cake:0.1.1-SNAPSHOT'
What's new:
Even more new argument handling methods
New methods have been added to support Fragment arguments with Int
and Serializable
types. Note that the latter of these still isn't a recommendation to pass around large objects as arguments, it's only meant to serve as a way to pass around some small objects like java.util.UUID
easier, without having to convert it to a String
and back.
These, again, conform to the naming convention of existing argument handling methods.
All of these Bundle
methods are also now documented and tested according to their documented behaviour. (Their internal implementation has also been unified to simplify them and make them safer.)
A new Navigator convenience method
The Navigator
interface now has a setStack(Iterable<Fragment>)
method to complement the existing setStack(vararg Fragment)
method, and avoid having to convert List
s and other iterables to arrays.
Version updates:
- Kotlin 1.3.20
0.1.0-SNAPSHOT
Third snapshot release of RainbowCake.
Update steps:
Update your dependency version:
implementation 'hu.autsoft:rainbow-cake:0.1.0-SNAPSHOT'
Optionally, update your screen templates.
What's new:
Shared ViewModels between Fragments
ViewModels by default are scoped to their Fragment, meaning a new instance is created for every new instance of the Fragment (barring configuration changes), and they are cleared when their Fragment is destroyed (as in their lifecycle completely ends).
There are use cases where it would make sense to share ViewModel instances between Fragments, and the getViewModelFromFactory
method now provides an opportunity for this in the form of an optional parameter. ViewModels may now be scoped to the current Activity or to a parent Fragment. For details, see the documentation.
A demo showcasing a ViewPager
where the pages share a ViewModel scoped to their parent Fragment is also available.
Navigation improvements
The Navigator
provided by the library contains a fade animation between screen changes by default. It's not possible to override this default behaviour.
You can override it globally, by providing new values for certain properties in your Activity that inherits from NavActivity
:
class MainActivity : SimpleNavActivity() {
override val defaultEnterAnim: Int = R.anim.slide_in_right
override val defaultExitAnim: Int = R.anim.slide_out_left
override val defaultPopEnterAnim: Int = R.anim.slide_in_left
override val defaultPopExitAnim: Int = R.anim.slide_out_right
}
You can also override animations one by one, by using overloads of the add
and replace
methods:
navigator?.add(SomeFragment(),
enterAnim = R.anim.slide_in_right,
exitAnim = R.anim.slide_out_left,
popEnterAnim = R.anim.slide_in_left,
popExitAnim = R.anim.slide_out_right
)
Note that a simple 0
may be used for any of these values to disable an animation altogether.
Be sure to check the documentation for all of the properties and methods mentioned above, as they contain much more information.
New argument handling methods
New methods have been added to support Fragment arguments with Boolean
and Parcelable
types. These conform to the naming convention of existing argument handling methods.
New executeCancellable
method
Previously, any coroutines started by making execute
calls in the ViewModel
were only cancelled when the ViewModel
was cleared. If you need to manage the Job
representing coroutines manually instead, you can now do so with the executeCancellable
method:
class MyViewModel : JobViewModel<MyViewState>(Default) {
private var loadingJob: Job? = null
fun loadData() {
loadingJob?.cancel()
loadingJob = executeCancellable {
// do something
}
}
}
Note that you shouldn't ever return this Job
to your Fragment, so do not do this, as the loadData
method here has an implicit return type of Job
, instead of Unit
:
class MyViewModel : JobViewModel<MyViewState>(Default) {
fun loadData() = executeCancellable {
// do something
}
}
Bug fixes and performance improvements (yes, really)
- Fragment backstack management fixes around the
replace
operation of theNavigator
implementation. - The
rootJob
inJobViewModel
is now aSupervisorJob
so that it's not cancelled altogether if a child coroutine fails (based on this article's advice). - The
coroutineContext
used by theCoroutineScope
inJobViewModel
is now only created once at instantiation. - Channel observations are now explicitly cleared when a
ChannelViewModel
is cleared.
Version updates:
- Kotlin 1.3.11
- Coroutines 1.1.0
- Android Gradle Plugin 3.3.0
0.0.2-SNAPSHOT
Second release of RainbowCake.
Update steps:
Update your dependency version:
implementation 'hu.autsoft:rainbow-cake:0.0.2-SNAPSHOT'
What's new:
Changes
withArgs
has been renamed to the more fitting applyArgs
(as it returns the Fragment
it was called on). withArgs
is still available, but should be migrated when possible. Automatic migration with intention action is available, should work project wide as well.
New features
Added an exhaustive
extension property to force when
to act as an expression and require all branches to be present, example usage:
when (viewState: ViewState) {
is Loading -> { /* Show loading */ }
is Errored -> { /* Show error */ }
is Ready -> { /* Show ready */ }
}.exhaustive
Version updates:
- Kotlin 1.3
- Coroutines 1.0.0
- Android Gradle Plugin 3.2.1