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:
Compose
is 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 parameters
forActivity
/Fragment
, I have a proposal on Reddit.RecyclerView.Adapter
is 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
Compose
andFlutter
.
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 withval
issynchronized
.
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.Set
is actually saved asSerialziable
and can’t keepParcelable
.
I suggest to useFlow
instead 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.