You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ViewHolder与ViewModel的区别是什么?请结合示例说明二者核心差异

Hey there! Let's break down the difference between ViewHolder and ViewModel—two Android components that sound similar but do completely different jobs. I'll walk through their core roles, use cases, and throw in code examples to make it crystal clear.

ViewHolder vs ViewModel: Core Differences

What is a ViewHolder?

Think of ViewHolder as a "view cache" for RecyclerView items. Back in the day, before this pattern was standard, we'd call findViewById() every time an item scrolled onto the screen—super inefficient, especially for long lists. The ViewHolder pattern fixes this by storing references to all the views in a single list item once, then reusing those references when the item is recycled.

It's strictly tied to the UI layer of individual list items—its only job is to hold onto views so we don't waste time re-finding them, and to bind data to those views when needed.

Example: RecyclerView ViewHolder

// Define the ViewHolder class inside your RecyclerView.Adapter
class NewsItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    // Cache references to the views in the item layout once
    val headlineTextView: TextView = itemView.findViewById(R.id.headline_text)
    val dateTextView: TextView = itemView.findViewById(R.id.date_text)
    val thumbnailImageView: ImageView = itemView.findViewById(R.id.thumbnail_img)

    // Bind data to the cached views when the item is recycled or loaded
    fun bind(article: NewsArticle) {
        headlineTextView.text = article.headline
        dateTextView.text = article.publishedDate
        Glide.with(itemView.context).load(article.thumbnailUrl).into(thumbnailImageView)
    }
}

// In your Adapter, create and reuse ViewHolders
class NewsAdapter(private var articles: List<NewsArticle>) : RecyclerView.Adapter<NewsItemViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsItemViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.news_item_layout, parent, false)
        return NewsItemViewHolder(view)
    }

    override fun onBindViewHolder(holder: NewsItemViewHolder, position: Int) {
        val article = articles[position]
        holder.bind(article)
    }

    override fun getItemCount() = articles.size

    fun updateData(newArticles: List<NewsArticle>) {
        articles = newArticles
        notifyDataSetChanged()
    }
}

What is a ViewModel?

ViewModel is part of Android Jetpack, and it's all about managing UI-related data and surviving configuration changes (like screen rotations, language switches, etc.). Its whole purpose is to separate your UI logic from your data logic—so your Activity/Fragment doesn't get cluttered with data loading, state management, or business rules.

ViewModel has a lifecycle tied to its host (Activity or Fragment) that outlives configuration changes. That means if you rotate your screen, the ViewModel stays alive, so you don't lose your data or have to re-fetch it.

Example: ViewModel for a News Feed Screen

// ViewModel class that handles data fetching and storage
class NewsViewModel : ViewModel() {
    private val _newsArticles = MutableLiveData<List<NewsArticle>>()
    // Expose immutable LiveData to the UI to prevent accidental data modification
    val newsArticles: LiveData<List<NewsArticle>> = _newsArticles

    init {
        // Fetch data when the ViewModel is initialized
        fetchLatestNews()
    }

    private fun fetchLatestNews() {
        // Use viewModelScope to run coroutines tied to the ViewModel's lifecycle
        viewModelScope.launch {
            try {
                // In real code, this would be a Retrofit call to your API
                val fetchedArticles = NewsApiService.getLatestArticles()
                _newsArticles.postValue(fetchedArticles)
            } catch (e: Exception) {
                // Handle error state (e.g., show a toast to the user)
                Log.e("NewsViewModel", "Failed to fetch articles", e)
            }
        }
    }

    // Optional: Add a method to refresh data manually
    fun refreshNews() {
        fetchLatestNews()
    }
}

// In your Fragment, use the ViewModel to drive the UI
class NewsFeedFragment : Fragment() {
    private lateinit var viewModel: NewsViewModel
    private lateinit var recyclerView: RecyclerView

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_news_feed, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        recyclerView = view.findViewById(R.id.news_recycler)
        recyclerView.adapter = NewsAdapter(emptyList())

        // Get the ViewModel instance—this survives screen rotations!
        viewModel = ViewModelProvider(this)[NewsViewModel::class.java]
        
        // Observe data changes from the ViewModel and update the UI
        viewModel.newsArticles.observe(viewLifecycleOwner) { articles ->
            (recyclerView.adapter as NewsAdapter).updateData(articles)
        }
    }
}

Key Differences at a Glance

Let's boil down the core distinctions between these two components:

  • Primary Purpose:
    • ViewHolder: Optimizes RecyclerView performance by caching item views (no repeated findViewById() calls).
    • ViewModel: Manages UI data and business logic, keeps data alive through configuration changes.
  • Lifecycle:
    • ViewHolder: Lives only as long as the list item is bound to the RecyclerView. When the item scrolls off-screen, the ViewHolder is recycled for a new item.
    • ViewModel: Lives as long as its host (Activity/Fragment) is in the foreground. Even if the host is destroyed due to a configuration change, the ViewModel persists until the host is permanently destroyed.
  • Scope:
    • ViewHolder: Limited to individual RecyclerView items—each item gets its own ViewHolder (recycled as needed).
    • ViewModel: Scoped to the host component (or even shared across fragments in the same activity) to manage page-level or shared data.
  • Responsibilities:
    • ViewHolder: Only interacts with views—holds references and binds data to them. No business logic here.
    • ViewModel: Handles data fetching (network/database), processes business rules, exposes data to the UI via LiveData or StateFlow.

Real-World Scenario Wrap-Up

Imagine you're using the news feed app:

  • The ViewModel fetches news articles from an API, stores them, and handles refreshes. If you rotate your phone, it keeps the loaded articles—no need to wait for a re-fetch.
  • The ViewHolder takes each article from the ViewModel's data, and binds the headline, date, and thumbnail to the corresponding views in the list item. It doesn't care where the data came from—it just displays it.

内容的提问来源于stack exchange,提问作者Vivek Ojha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 09:27:33