Skip to content

Instantly share code, notes, and snippets.

@tw-Frey
Created January 7, 2022 04:24
Show Gist options
  • Select an option

  • Save tw-Frey/8eebce6b857119991149b5285f1dc6f6 to your computer and use it in GitHub Desktop.

Select an option

Save tw-Frey/8eebce6b857119991149b5285f1dc6f6 to your computer and use it in GitHub Desktop.
User events in RecyclerViews

If the action is produced further down the UI tree, like in a RecyclerView item or a custom View, the ViewModel should still be the one handling user events.

For example, suppose that all news items from NewsActivity contain a bookmark button. The ViewModel needs to know the ID of the bookmarked news item. When the user bookmarks a news item, the RecyclerView adapter does not call the exposed addBookmark(newsId) function from the ViewModel, which would require a dependency on the ViewModel. Instead, the ViewModel exposes a state object called NewsItemUiState which contains the implementation for handling the event:

data class NewsItemUiState(
    val title: String,
    val body: String,
    val bookmarked: Boolean = false,
    val publicationDate: String,
    val onBookmark: () -> Unit
)

class LatestNewsViewModel(
    private val formatDateUseCase: FormatDateUseCase,
    private val repository: NewsRepository
)
    val newsListUiItems = repository.latestNews.map { news ->
        NewsItemUiState(
            title = news.title,
            body = news.body,
            bookmarked = news.bookmarked,
            publicationDate = formatDateUseCase(news.publicationDate),
            // Business logic is passed as a lambda function that the
            // UI calls on click events.
            onBookmark = {
                repository.addBookmark(news.id)
            }
        )
    }
}

This way, the RecyclerView adapter only works with the data that it needs: the list of NewsItemUiState objects. The adapter doesn’t have access to the entire ViewModel, making it less likely to abuse the functionality exposed by the ViewModel. When you allow only the activity class to work with the ViewModel, you separate responsibilities. This ensures that UI-specific objects like views or RecyclerView adapters don't interact directly with the ViewModel.

Warning: It's bad practice to pass the ViewModel into the RecyclerView adapter because that tightly couples the adapter with the ViewModel class.

@tw-Frey

tw-Frey commented Jun 29, 2022

Copy link
Copy Markdown
Author

@tw-Frey

tw-Frey commented Jun 29, 2022

Copy link
Copy Markdown
Author

我的解讀是

除非有必要

不然 model 和 model 之間

應該用 data 來溝通

不要 誰嵌誰

降低耦合性

model 重用性可以提高

而且

model 故障時

要翻找的對象也比較少

反過來說

也比較好 測試 (Unit Test)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment