MimiSDK 5 Migration Guide¶
This document outlines the various changes required to migrate to MimiSDK 5 from a previous 4.x.x
version of MimiSDK.
MimiSDK 5 introduces several API-breaking changes to be aware of.
What is new¶
The following section describes all changes that are considered breaking API, removal of previously deprecated functionality or significant behavioral changes.
Configuration¶
- The initial configuration and previously deprecated flag
alwaysShowHearingResults
insideMimiConfiguration
class, has been removed as detailed hearing results are no longer visible for the Consumer Electronic variant of the mSDK. - The legacy
ConfigurationController
insideMimiCore
has been replaced by a brand new version of the class with the same name. This new class exposes now theremoteConfig
value to be consumed as aMimiObservable
. For more info about this and other similar methods, please scroll to the New Observable Pattern section.
ProcessingController¶
The ProcessingController.resetParams()
method is no longer a publicly available method as it is meant to be used only internally.
New way of handling Forcibly Logged Out Users¶
In this new version we also removed the legacy MimiCore.failedToRefreshTokenForUser
object that listened constantly to unsuccessful token auth refresh events that would eventually log the current user out of the session.
From now on, the recommended way to handle these events is to observe the UserController.mimiUser
and its loadingState
property, and react accordingly (maybe showing an alert dialog when this one gets the value LoadingState.Failure
with its cause
field set to MimiCoreException.ForciblyLoggedOut
.
New Observable Pattern¶
In this new 5.0.0
version of the MimiSDK, we took the decision of getting rid of the classic Android Listener/Callback approach due to the constraints that these imposed upon new written code. Instead, we decided to adopt the Observable/Subscriber pattern, thanks to which, integrators will be able to sign up for updates on specific variables.
When these variables change, or certain events get triggered internally, their new values will be emitted and consumed reactively by those who have subscribed previously to their updates.
With this new approach, we will avoid to manually forward these events across multiple classes and also improve the visual clarity of critical values such as the mimiUser
or the latestTestResults
.
This was particularly painful for scenarios where the final value of a parameter that was meant to be read by the integrators, was dependent on the complete success of diverse and chained I/O operations. If this value was not mapped correctly, this could lead to bugs related with incorrect visual representations within our UI components.
New Mimi Components¶
To achieve and implement the new Observable pattern mentioned above, we introduced several new constructs, classes and methods such as:
MimiObservable and MimiObserver¶
MimiObservable<T>
is a new component that encapsulates any object of type T
allowing integrators to subscribe to stream of subsequent updates on this object by registering a MimiObserver
on it.
Please note that the observe
method will never finish unless the integrator removes/disposes the reference to the observer method manually. Also this is a suspended method, so in order to receive asynchronous updates of the observed parameter, one will need to call it from within a coroutine scope:
myCoroutineScope.launch {
MimiCore.userController.mimiUser.observe { newMimiUser ->
// execute any action on the fetched user
}
}
myCoroutineScope.cancel()
AsyncState and LoadingState¶
AsyncState
is a special read only class, that maps any given value, to a given LoadingState
. This construct becomes really handy when dealing with objects or variables that are meant to change or be updated through the lifecycle of the MSDK, such as a MimiUser
or MimiTestResults
.
Since each value is mapped to a loading state, one can interpret more accurately, whether the read value is:
- In the middle of an update -> InProgress
- Valid or Idle -------------> Done
- in an error state ----------> Failure
Another interesting scenario that can be found very often in this new release, is wrapping a given object with both MimiObservable
and AsyncState
classes.
In this case, after subscribing to objects wrapped in this specific way, one will listen to updates containing information of a given value and its associated loading state on that given moment.
A good example of this is the mimiUser
contained inside the MimiCore.testsController
:
val mimiUser: MimiObservable<AsyncState<MimiUser?>>
val userValue: MimiUser = mimiUser.state.value
val userLoadingState: LoadingState = mimiUser.state.loadingState
MimiObservable
via the x.state.value
accessor is not encouraged, as it can lead to undesired loss of sync with the original MimiObservable
parameter.
@MsdkInternalApi Annotation¶
Due to the multi-modular nature of our MSDK, sometimes we need to declare certain variables or methods as public API even though they are not meant to be accessed or used by integrators.
In order to identify these only-for-internal-use structures, we created a specific annotation for it. The @MsdkInternalApi
will help integrators to notice when they are trying to use a restricted component, by throwing a visual IDE compilation warning.
The usage of constructs tagged with this specific annotation by integrators is highly discouraged, as this code may change or be removed without prior notice on future releases, as well as cause unexpected issues or errors that can alter the internal logic of the mSDK.
New Mimi Core and Controller classes¶
We have reworked internally the structure of the singleton MimiCore
object needed to access the main SDK controllers.
Nevertheless from a external/public facing point of view, its usage will remain the same as in the legacy version, having to provide a valid set of credentials via the MimiCore.start()
method in order to run all the Mimi logic correctly.
Please note however, that some of the legacy functionality might have been migrated and/or renamed some methods among certain controllers.
Please check the Changelog for the specific method renaming.
AuthController¶
The legacy AuthController
class, has been removed and its functionality migrated to the UserController
class.
We need to make a special mention here as well, as the authentication logic is now handled entirely by the method suspend fun authenticate(route: MimiAuthRoute): MimiUser
inside the UserController
class.
Depending on the concrete integration needs, one will need to provide the specific MimiAuthRoute
sealed class.
TestsController¶
We have limited the handling of the HearingTest
class to the strictly necessary actions. Therefore all methods that loaded (individually or in bulk) or deleted Hearing Tests were removed.
Instead we created equivalent methods to execute their counterpart logic on MimiTestResults
objects, namely:
- submitTest(hearingTest: HearingTest): Unit
will submit a new Hearing Test
- submitTestForResult(hearingTest: HearingTest): MimiTestResult
will submit a new Hearing Test and get returned the MimiTestResult
associated with that previously submitted test.
- deleteTestResult(id: String): Unit
will delete the test result associated with that id
.
- loadLatestTestResults(): MimiTestResults
will load a MimiTestResults
object filled with the latest test results for the available Test Paradigms.
Deprecation of Controller Listeners¶
As we mentioned above, we wanted to get rid of the classic listener pattern to inform about changes on the main pieces of information in our SDK. Therefore, the TestsControllerListener
and UserControllerListener
interface classes have also been removed.
From now on, the integrators will need to subscribe to the newly latestTestResults: MimiObservable<AsyncState<MimiTestResults>>
and the mimiUser: MimiObservable<AsyncState<MimiUser?>>
inside the TestController
and UserController
classes respectively to listen for changes happening on the Latest Tests and the current Mimi User objects.