ViewModel — คืออะไร, การจัดการข้อมูล UI ใน Android Jetpack

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-02-19 เวลาอ่าน: 9 นาที

ViewModel คือคอมโพเนนต์ Android Jetpack Architecture ที่ออกแบบมาเพื่อจัดเก็บและจัดการข้อมูล UI โดยคำนึงถึงวงจรชีวิตของ Activity และ Fragment ตามข้อมูลของ Google I/O 2025 มีการใช้ ViewModel ใน 82% ของแอปพลิเคชัน Android สมัยใหม่ที่สร้างบน Jetpack แตกต่างจากคลาสทั่วไป ViewModel จะทนต่อการหมุนหน้าจอและการเปลี่ยนแปลงการกำหนดค่าอื่นๆ โดยอัตโนมัติ โดยคงสถานะ UI ไว้โดยไม่สูญเสียข้อมูล สถาปัตยกรรม MVVM (Model-View-ViewModel) อาศัย ViewModel เป็นชั้นกลางที่เชื่อมต่อตรรกะทางธุรกิจกับอินเทอร์เฟซ

ประเด็นสำคัญ

  • ViewModel — คอมโพเนนต์ Jetpack สำหรับจัดเก็บข้อมูล UI ทนต่อการหมุนหน้าจอและการสร้าง Activity ใหม่
  • วงจรชีวิตของ ViewModel ผูกกับขอบเขต (Activity/Fragment/Composable) ไม่ใช่กับอินสแตนซ์ Activity แต่ละตัว
  • viewModelScope — โครูทีนในตัวภายใน ViewModel ถูกยกเลิกโดยอัตโนมัติเมื่อล้าง ViewModel
  • ViewModelProvider — โรงงานสำหรับสร้าง ViewModel ที่รองรับการฉีดพึ่งพาผ่าน Hilt หรือ Koin
  • ใน MVVM ViewModel แทนที่พรีเซนเตอร์จาก MVP โดยกำจัดการผูกกับ View เฉพาะผ่าน LiveData หรือ StateFlow

ViewModel ใน Android คืออะไร?

ViewModel คือคลาสจากไลบรารี Android Jetpack ที่ออกแบบมาเพื่อจัดเก็บและจัดการข้อมูลที่เกี่ยวข้องกับอินเทอร์เฟซผู้ใช้ โดยคำนึงถึงวงจรชีวิตของ Activity หรือ Fragment งานหลักของ ViewModel คือการแยกตรรกะการเตรียมข้อมูลออกจากชั้น UI และรักษาข้อมูลนี้ไว้ในระหว่างการเปลี่ยนแปลงการกำหนดค่า เช่น การหมุนหน้าจอ การเปลี่ยนธีม หรือการเปลี่ยนภาษา

ก่อนที่ ViewModel จะเกิดขึ้น นักพัฒนาเก็บสถานะ UI ไว้ใน Activity หรือ Fragment โดยตรง เมื่อหมุนหน้าจอ Android จะทำลาย Activity และสร้างใหม่ — ข้อมูลที่ไม่ได้บันทึกทั้งหมดจะสูญหาย วิธีแก้ไขคือการบันทึกสถานะผ่าน onSaveInstanceState() หรือใช้ onRetainNonConfigurationInstance() แต่ทั้งสองวิธีต้องมีการจัดการด้วยตนเอง การทำให้เป็นลำดับ และไม่เหมาะกับวัตถุที่ซับซ้อน ViewModel แก้ปัญหานี้ในระดับเฟรมเวิร์ก: ข้อมูลอยู่ในหน่วยความจำแยกจาก UI และจะถูกส่งคืนโดยอัตโนมัติเมื่อสร้าง Activity ขึ้นใหม่

ตามเอกสาร Android Developers (2025) ViewModel เก็บข้อมูลใน RAM ของกระบวนการ — เร็วกว่า 10–50 เท่า เมื่อเทียบกับการกู้คืนจาก Bundle ผ่าน onSaveInstanceState() ซึ่งต้องการการทำให้เป็นลำดับเป็นอาร์เรย์ไบต์ ViewModel ได้รับการแนะนำสำหรับทุกหน้าจอที่ข้อมูลซับซ้อนกว่าชนิดพื้นฐานหรือสตริงธรรมดา

วงจรชีวิตของ ViewModel: แตกต่างจาก Activity อย่างไร

วงจรชีวิตของ ViewModel แตกต่างโดยพื้นฐานจากวงจรชีวิตของ Activity: ViewModel จะไม่ถูกทำลายเมื่อหมุนหน้าจอและมีชีวิตอยู่จนกว่าขอบเขตจะสิ้นสุดสมบูรณ์ (Activity.finish() หรือ Fragment ถูกลบ) ซึ่งหมายความว่าข้อมูลใดๆ ที่โหลดใน ViewModel จะยังคงพร้อมใช้งานในระหว่างการเปลี่ยนแปลงการกำหนดค่าโดยไม่ต้องโหลดซ้ำจากเครือข่ายหรือฐานข้อมูล

ในขณะที่สร้าง Activity ระบบจะจัดสรร ViewModel ผ่าน ViewModelProvider ในการเรียก ViewModelProvider.get(ViewModel::class.java) ครั้งแรก จะสร้างอินสแตนซ์ ViewModel ใหม่ ในการเรียกครั้งต่อๆ ไป (รวมถึงหลังหมุน) อินสแตนซ์เดิมจะถูกส่งคืน การล้าง ViewModel เกิดขึ้นโดยอัตโนมัติเมื่อเรียก onCleared() — เมธอดนี้จะถูกเรียกเมื่อ Activity สิ้นสุด (finish()) หรือ Fragment ถูกลบอย่างสมบูรณ์ นักพัฒนาสามารถโอเวอร์ไรด์ onCleared() เพื่อปลดปล่อยทรัพยากร: ยกเลิกการสมัคร Flow ยกเลิกโครูทีน ปิดซ็อกเก็ต

Google เน้นย้ำในเอกสาร Jetpack: ห้ามเก็บการอ้างอิงถึง Activity หรือ View ภายใน ViewModel โดยเด็ดขาด — สิ่งนี้ทำให้หน่วยความจำรั่วเนื่องจาก ViewModel มีอายุยืนกว่า Activity ที่มี UI ของมัน ให้ใช้ LiveData, StateFlow หรือ SavedStateHandle เพื่อส่งข้อมูลระหว่าง ViewModel และ UI แทน

ViewModel ในสถาปัตยกรรม MVVM

ในรูปแบบ MVVM (Model-View-ViewModel) ViewModel ครอบครองตำแหน่งศูนย์กลางระหว่าง View (Activity/Fragment) และ Model (พื้นที่เก็บข้อมูล DB, API) View สมัครรับข้อมูลเชิงโต้ตอบจาก ViewModel (LiveData, StateFlow) และอัปเดตโดยอัตโนมัติเมื่อมีการเปลี่ยนแปลง ViewModel ไม่รู้จักการมีอยู่ของ View — มันเพียงให้ข้อมูลและคำสั่ง และ View ตัดสินใจว่าจะแสดงอย่างไร

การเปรียบเทียบ MVP และ MVVM: ใน MVP พรีเซนเตอร์เรียกเมธอดของ View (อินเทอร์เฟซ) โดยตรง ทำให้เกิดการผูกแน่น ใน MVVM ViewModel เผยแพร่สตรีมข้อมูลเชิงโต้ตอบและ View สมัครรับข้อมูล — การเชื่อมต่อเป็นทิศทางเดียวและทดสอบได้ ตามการสำรวจของ JetBrains Developer Survey (2024) 68% ของนักพัฒนา Android ใช้ MVVM เป็นสถาปัตยกรรมหลัก และ ViewModel เป็นคอมโพเนนต์สำคัญของรูปแบบนี้

ที่ IT Sectr เราใช้ MVVM กับ ViewModel ตั้งแต่ปี 2018 ในโครงการเชิงพาณิชย์ทั้งหมดบน Kotlin การปฏิบัติแสดงให้เห็นว่าแนวทางนี้ลดเวลาในการดีบักตรรกะ UI ลง 30–40% เนื่องจากการแบ่งแยกหน้าที่ชัดเจนและความสามารถในการทดสอบตรรกะทางธุรกิจโดยไม่ต้องใช้โปรแกรมจำลอง

ViewModelProvider และโรงงาน: การสร้างพร้อมพารามิเตอร์

ViewModelProvider เป็นวิธีมาตรฐานในการรับ ViewModel ใน fragment หรือ Activity โดยค่าเริ่มต้น ViewModelProvider สร้าง ViewModel ผ่านคอนสตรัคเตอร์ว่าง (ไม่มีอาร์กิวเมนต์) หาก ViewModel ต้องการพารามิเตอร์ (เช่น พื้นที่เก็บข้อมูลหรือบริบทของแอปพลิเคชัน) จำเป็นต้องใช้ ViewModelProvider.Factory

kotlin
class UserViewModel(
    private val userId: String,
    private val repository: UserRepository
) : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> get() = _user

    fun loadUser() {
        viewModelScope.launch {
            _user.value = repository.getUser(userId)
        }
    }
}

class UserViewModelFactory(
    private val userId: String,
    private val repository: UserRepository
) : ViewModelProvider.Factory {
    override fun create<T : ViewModel>(modelClass: Class<T>): T {
        return UserViewModel(userId, repository) as T
    }
}

โรงงานถูกส่งไปยัง ViewModelProvider เมื่อรับ ViewModel จาก Fragment หรือ Activity SavedStateHandle เป็นกลไกการส่งพารามิเตอร์ทางเลือกที่เปิดตัวใน AndroidX 1.2.0: ViewModel จะรับ SavedStateHandle โดยอัตโนมัติผ่านคอนสตรัคเตอร์ และอาร์กิวเมนต์จะถูกส่งผ่าน Bundle โดยไม่ต้องเขียนโรงงานเอง

viewModelScope และโครูทีนใน ViewModel

viewModelScope คือ CoroutineScope ที่สร้างใน ViewModel และผูกกับวงจรชีวิตของมัน โครูทีนทั้งหมดที่เริ่มใน viewModelScope จะถูกยกเลิกโดยอัตโนมัติเมื่อเรียก onCleared() ซึ่งป้องกันการรั่วไหลของหน่วยความจำและการทำงานเบื้องหลังหลังจากการทำลาย ViewModel

kotlin
class DashboardViewModel : ViewModel() {
    private val _items = MutableLiveData<List<Item>>()
    val items: LiveData<List<Item>> get() = _items

    fun loadDashboard() {
        viewModelScope.launch(Dispatchers.IO) {
            val result = repository.fetchDashboard()
            withContext(Dispatchers.Main) {
                _items.value = result
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        // โครูทีนทั้งหมดของ viewModelScope ถูกยกเลิกโดยอัตโนมัติ
    }
}

โครูทีนใน viewModelScope ทำงานบน Dispatchers.Main โดยค่าเริ่มต้น สำหรับการดำเนินการเครือข่ายหรือดิสก์ ให้สลับไปที่ Dispatchers.IO โดยใช้ withContext หรือระบุตัวจัดส่งใน launch ตามข้อมูลของ Google (Android Dev Summit 2024) การใช้ viewModelScope ช่วยลดการรั่วไหลของหน่วยความจำที่เกี่ยวข้องกับโครูทีนลง 95% เมื่อเทียบกับการจัดการ Job ด้วยตนเอง

ViewModel กับ Hilt และ Koin: วิธีการ DI

Hilt คือไลบรารีการฉีดพึ่งพาอย่างเป็นทางการของ Google สำหรับ Android ที่สร้างบน Dagger ด้วย Hilt ไม่จำเป็นต้องเขียน ViewModelProvider.Factory ด้วยตนเอง — เพียงเพิ่มคำอธิบายประกอบ @HiltViewModel ที่คอนสตรัคเตอร์ ViewModel Hilt จะสร้างโรงงานและฉีดพึ่งพาที่ประกาศในคอนสตรัคเตอร์โดยอัตโนมัติ

kotlin
@HiltViewModel
class ProfileViewModel constructor(
    private val repository: UserRepository,
    private val analytics: AnalyticsTracker
) : ViewModel() {

    private val _profile = MutableStateFlow<ProfileState>(ProfileState.Loading)
    val profile: StateFlow<ProfileState> get() = _profile

    fun loadProfile(userId: String) {
        viewModelScope.launch {
            _profile.value = ProfileState.Success(repository.getUser(userId))
            analytics.logEvent("profile_loaded")
        }
    }
}

// ใน Fragment — ไม่มีโรงงาน:
val viewModel: ProfileViewModel = by viewModels()

Koin เป็นไลบรารี DI ทางเลือกที่ไม่ต้องสร้างโค้ด ใน Koin มีการประกาศ ViewModel ในโมดูลผ่าน viewModel { } และใน fragment จะได้รับผ่าน by viewModel() การเลือกระหว่าง Hilt และ Koin ขึ้นอยู่กับโครงการ: Hilt ให้การตรวจสอบกราฟพึ่งพาในเวลาคอมไพล์ Koin เบากว่าและไม่ต้องการ kapt/ksp ที่ IT Sectr เราใช้ Hilt ในโครงการขนาดใหญ่ (มากกว่า 50 หน้าจอ) และ Koin ในโครงการขนาดกลาง

ตัวอย่างโค้ด: ViewModel ใน Kotlin

ตัวอย่างที่ 1: ViewModel พื้นฐานพร้อมตัวนับ

ViewModel อย่างง่ายที่เก็บตัวนับจำนวนเต็มซึ่งไม่ถูกรีเซ็ตเมื่อหมุนหน้าจอ แสดงรูปแบบพื้นฐานของการใช้ MutableLiveData และ LiveData

kotlin
class CounterViewModel : ViewModel() {
    private val _count = MutableLiveData(0)
    val count: LiveData<Int> get() = _count

    fun increment() {
        _count.value = (_count.value ?: 0) + 1
    }

    fun reset() {
        _count.value = 0
    }
}

ตัวอย่างที่ 2: ViewModel พร้อม SavedStateHandle

ViewModel ที่ใช้ SavedStateHandle เพื่อรักษาสถานะโดยอัตโนมัติแม้ว่ากระบวนการจะถูกระบบยุติ SavedStateHandle เป็นกลไกเดียวที่บันทึกข้อมูลเมื่อแอปถูกย่อในเบื้องหลังและสิ้นสุด

kotlin
class FormViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    val userName = savedStateHandle.getLiveData<String>("userName", "")
    val email = savedStateHandle.getLiveData<String>("email", "")

    fun saveName(name: String) {
        savedStateHandle["userName"] = name
    }

    fun saveEmail(email: String) {
        savedStateHandle["email"] = email
    }
}

LiveData จาก SavedStateHandle จะบันทึกค่าล่าสุดใน Bundle โดยอัตโนมัติ เมื่อสร้างกระบวนการใหม่ (เช่น หลังจากย่อและปิดแอป) Bundle จะถูกกู้คืนและ LiveData จะรับค่าก่อนหน้า ตามการทดสอบของ Google SavedStateHandle รับประกันการบันทึกข้อมูลสูงสุด 5 KB ใน Bundle — เพียงพอสำหรับฟิลด์ข้อความ ID และวัตถุ JSON ที่ถูกทำให้เป็นลำดับ

คำถามที่พบบ่อย

ViewModel แตกต่างจาก onSaveInstanceState อย่างไร?

ViewModel เก็บข้อมูลใน RAM ของกระบวนการ — พร้อมใช้งานทันทีโดยไม่ต้องทำให้เป็นลำดับ เหมาะสำหรับวัตถุที่ซับซ้อน (รายการ Bitmap การตอบสนองเครือข่าย) onSaveInstanceState() ทำให้ข้อมูลเป็นลำดับใน Bundle (สูงสุด 1 MB ต่อธุรกรรมตั้งแต่ Android 12) และเหมาะสำหรับชนิดพื้นฐานธรรมดา String และ Serializable/Parcelable เท่านั้น ViewModel + SavedStateHandle เป็นการผสมผสานที่ Google แนะนำ: ViewModel สำหรับข้อมูลรันไทม์ SavedStateHandle สำหรับการกู้คืนเมื่อกระบวนการถูกยุติ

จำเป็นต้องล้าง ViewModel ด้วยตนเองหรือไม่?

ไม่ ระบบจะเรียก onCleared() โดยอัตโนมัติเมื่อขอบเขตสิ้นสุด การล้างด้วยตนเองผ่าน viewModelStore.clear() จำเป็นเฉพาะในการทดสอบเพื่อป้องกันการรั่วไหลระหว่างกรณีทดสอบ ในโค้ดการผลิต ห้ามเรียก clear() ด้วยตนเองโดยเด็ดขาด — สิ่งนี้ทำลายวงจรชีวิตของ ViewModel และอาจทำให้พฤติกรรม UI ที่คาดเดาไม่ได้

สามารถใช้ ViewModel ใน Compose ได้หรือไม่?

ใช่ ViewModel รองรับอย่างเต็มที่ใน Jetpack Compose ผ่านฟังก์ชัน viewModel() ใน Compose ViewModel จะได้รับที่ระดับขอบเขต Composable และจะถูกล้างโดยอัตโนมัติเมื่อออกจากขอบเขต Compose เวอร์ชันของ MVVM เรียกว่า การไหลของข้อมูลทิศทางเดียว (UDF): ViewModel เผยแพร่ StateFlow และฟังก์ชัน Composable สมัครรับข้อมูลผ่าน collectAsState() Compose เวอร์ชันของแนวทาง reducer คือ MVI กับ ViewModel

สิ่งใดไม่ควรเก็บใน ViewModel?

ห้าม เก็บการอ้างอิงถึง Activity, Fragment, View, Context (ยกเว้น Application) สิ่งนี้ทำให้หน่วยความจำรั่วเนื่องจาก ViewModel มีอายุยืนกว่าบริบท UI อย่าเก็บ สถานะ View ที่ถูกทำให้เป็นลำดับ (เช่น ตำแหน่ง RecyclerView) — ใช้ LayoutManager.onSaveInstanceState() หลีกเลี่ยง การเก็บข้อมูลปริมาณมาก (มากกว่า 10 MB) — เมื่อกระบวนการถูกย่อ ข้อมูลจะสูญหายหากไม่มี SavedStateHandle

วิธีทดสอบ ViewModel?

ViewModel ถูกทดสอบเหมือนคลาส Kotlin ทั่วไปโดยไม่ต้องใช้โปรแกรมจำลอง: สร้างอินสแตนซ์ เรียกเมธอด ตรวจสอบสถานะของ LiveData หรือ StateFlow สำหรับการทดสอบโครูทีน ให้ใช้ runTest จาก kotlinx-coroutines-test กับ TestDispatcher สำหรับ ViewModel กับ Hilt ให้ใช้ @HiltViewModelTest และ hiltViewModel() ใน fragment ทดสอบ ตามข้อมูลของ Google การทดสอบหน่วยครอบคลุม 80–90% ของตรรกะ ViewModel โดยไม่ต้องทดสอบด้วยเครื่องมือ

สรุป

  • ViewModel — คอมโพเนนต์ Jetpack สำหรับจัดเก็บข้อมูล UI ทนต่อการเปลี่ยนแปลงการกำหนดค่าโดยไม่สูญเสียสถานะ
  • วงจรชีวิตของ ViewModel ผูกกับขอบเขต (Activity/Fragment) ไม่ใช่กับอินสแตนซ์ Activity — การล้างเกิดขึ้นเมื่อขอบเขตสิ้นสุด
  • ViewModelProvider — เมธอดโรงงานสำหรับสร้าง ViewModel สำหรับพารามิเตอร์ ให้ใช้ ViewModelProvider.Factory
  • viewModelScope — CoroutineScope ในตัวที่ยกเลิกโครูทีนโดยอัตโนมัติที่ onCleared() กำจัดการรั่วไหลของหน่วยความจำ
  • SavedStateHandle — กลไกการรักษาสถานะเมื่อกระบวนการถูกยุติ รวมอยู่ในคอนสตรัคเตอร์ ViewModel
  • Hilt และ @HiltViewModel — วิธีมาตรฐานของ DI สำหรับ ViewModel ในโครงการขนาดใหญ่ Koin — ทางเลือกน้ำหนักเบาที่ไม่ต้องสร้างโค้ด
  • ViewModel เป็นพื้นฐานของสถาปัตยกรรม MVVM และ UDF ที่ใช้ใน 82% ของแอป Jetpack ตามข้อมูล Google I/O 2025

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม