MVVM - TsukaP/AndroidProject2019 GitHub Wiki
Rule
View
What is View?
- Activity
- Fragment
- Custom view
- ViewHolder of recyclerView
Role
- Set layout(xml) content.
- Create
ViewMdodel
. - Bind viewModel to layout
- Transition screen.
- Show dialog (or toast message, snackBar).
- Detect lifeCycle and call need logic.
Taboo
- Implement logic
- if ~ else
- for
- when
- and more...
- Event handling
- onClick
- touch
- and more...
- Direct access to
Model
ViewModel
What is ViewModel?
- Created 1 to 1 with
View
(There are also exceptions.)
Role
- It has data for
View
.- Update data
- Format string
- Change color, visivility, ...
- Handling each events.
- Buttton click
- Timer
- and more...
- Call business logic on
Model
.
Taboo
- Has
android.content.Context
- Has
Activity
Model
What is Model?
- It is business logic layer.
Role
As above.
Taboo
- Has
android.content.Context
- Has
Activity
onClick
event on ViewModel
How to handling It is a premise that ViewModel
is bind to View
.
layout.xml
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{viewModel::onClickButton}"/>
ViewModel
fun onClickButton(@SuppressWarnings("unused") view: View) {
// Handling button click event.
}
How to transition screen when click button.
View
implements Navigator
.
And pass to ViewModel
.
Navigator
interface MainNavigator {
fun navigateToNextScreen()
fun showDialog(message: String)
}
View
class MainActivity : AppCompatActivity(), MainNavigator {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MainViewModel(this)
// and bind this viewModel
}
override fun navigateToNextScreen() {
// Start Next screen
}
override fun showDialog(message: String) {
// Show dialog with message.
}
}
ViewModel
class MainViewModel(
private val navigator: MainNavigator) {
fun onClickButton(@SuppressWarnings("unused") view: View) {
navigator.navigateToNextScreen()
}
}
R.string.xxxxx
in ViewModel
How to use Use context wrapper class.
ResourceResolver
class ResourceResolver(private val context: Context) {
fun getString(@StringRes resId: Int): String = context.getString(resId)
}
Create ResourceResolver
instance on View
.
And pass to Viewmodel
like Navigator
.
And more tips
Load image with URL
Use @BindingAdapter
.
@BindingAdapter("src")
fun bindAdapterImageView(imageView: ImageView, url: String?) {
Glide.with(imageView.context)
.load(url)
.into(imageView)
}
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:src="@{viewModel.imageUrl}" />
RecyclerView.Adapter#notifyDataSetChanged
Use this solution. ObservableListRecyclerAdapter
Pass item data list to this adapter.
So, auto detect and call notifyDataSetChanged
when change data on observableList
.