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 forView.
    • 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

How to handling onClick event on ViewModel

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()
    }
}

How to use R.string.xxxxx in ViewModel

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.