Abstract #
MVB is my new architecture standing for Model-View-Bridge. Now, it only has an Android implementation,
but the pattern is applicable to every platform that supports Kotlin. The UI part uses the traditional View without
DataBinding, and the Kt part hides ViewModel, resulting in much less code and clearer logic.
Other points:
Composeis the most concise declarative UI framework, and also the most flexible in terms of custom views. However, its recombination mechanism inevitably reconstructs massive objects, resulting in its low upper performance limit.Regarding
navigation parametersforActivity/Fragment, I have a proposal on Reddit.RecyclerView.Adapteris the most common among components with complex writing styles, whereas my encapsulated KRecyclerViewAdapter arranges list items asCompose.For the UI part, I have a new design pattern proposal of which the expected effect is much better than
ComposeandFlutter.
Overall, I suggest MVB if you haven’t switched to Compose from View at present. In the future, there would be a new
imperative UI mode based on that proposal implementation in which MVB mode would still work.
Setup #
android{
buildFeatures {
viewBinding true
}
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach{
kotlinOptions.freeCompilerArgs += "-Xcontext-receivers"
}
dependencies {
implementation 'io.github.shawxingkwok:android-util-view:1.0.8'
implementation 'io.github.shawxingkwok:mvb-android:1.0.7'
}
android{
buildFeatures {
viewBinding = true
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions.freeCompilerArgs += "-Xcontext-receivers"
}
dependencies {
implementation("io.github.shawxingkwok:android-util-view:1.0.8")
implementation("io.github.shawxingkwok:mvb-android:1.0.7")
}`
Usage #
Examples are all withFragment, but also applicable onComponentActivity(a super class ofAppCompatAtivity).
rmb #
This is the abbreviation of remember, meaning the value is alive across the configuration change (e.g. rotation).
Switch from the traditional way as below.

↓

Initialization of the property declared withvalissynchronized.
save #
Direct #
Saved values are not only alive across the configuration change, but also restorable from the killed process.

↓


↓


↓

Saved value types should follow Parcelize rules. Please note that there is a mistake in the official document.Setis actually saved asSerialziableand can’t keepParcelable.
I suggest to useFlowinstead ofLiveData, though it takes some time to learn.
Rules below are same tosaveMutableStateFlow,saveMutableSharedFlow,saveMutableLiveData, and not limited withval/var.
Transform #
You could also save values with any type by appending transform after save with the converted values following
Parcelize rules.

The lambda convert keeps alive after its lifecycle owner is killed by the application. Therefore,
don’t reference callables from its owner to avoid memory leaks.Parcelable component #
Sometimes you need to pass KClass<out Parcelable> as the parcelable component. Besides, there could be no more than 1
parcelable subtype.

observe #
The delegated values via rmb / save are easily observable if it’s Flow / LiveData. The latter observe lambdas
are active between every onStart and onStop, which is generally used for linking value to UI state.

↓

mvbScope #
This is viewModelScope of the hidden MVBViewModel. This coroutineScope is not affected by the configuration change,
and cancelled only when its owner ComponentActivity / Fragment is killed by user presses back or low memory.
Besides, it’s not static but actually an extensive property. Check out the source code, and you will find there is no
memory leak.

Format #
Take an example of simulating the stopwatch page in the IOS clock with concise code below.
Utils and Components for reusable and complex parts #

See KRecyclerViewAdapter if it’s new to you.

Static processing #
For example, declaring components and enabling them in ComponentActivity.onCreate / Fragment.onViewCreated

Bridge #
Declaring variable data sources via rmb and save, and linking them to UI state via appending observe.


Fixed listeners #
I suggest to put fixed listeners here or below, allowing for variating data source or navigating to other pages.

Or this style

Some functions from other libraries are independent with MVB, e.g.
binding(XxBinding::bind),
onClick,
and updateIf.