onStop — การซ่อน Activity ในวงจรชีวิต Android

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

onStop — เมธอดของวงจรชีวิต Activity ใน Android ซึ่งถูกเรียกโดยระบบเมื่อ Activity ไม่ปรากฏแก่ผู้ใช้อีกต่อไป Activity จะเปลี่ยนไปยังสถานะ Stopped หลังจากที่ Activity ใหม่ครอบคลุมมันอย่างสมบูรณ์ หรือเมื่อแอปพลิเคชันถูกย่อ ในเมธอด onStop นักพัฒนาต้องหยุดแอนิเมชัน ปล่อยทรัพยากรกล้องและเซนเซอร์ และบันทึกร่างของข้อมูลที่ป้อน ตาม Android Vitals (Google, 2025) การจัดการ onStop อย่างถูกต้องจะลดจำนวน ANR (แอปพลิเคชันไม่ตอบสนอง) เมื่อย่อแอปพลิเคชันลง 35% หลังจาก onStop ระบบสามารถเรียก onRestart (กลับไปยังหน้าจอ) หรือ onDestroy (สิ้นสุดสมบูรณ์) เอกสาร Android Developers เกี่ยวกับวงจรชีวิต Activity อธิบาย onStop ว่าเป็นขอบเขตระหว่างสถานะที่มองเห็นและมองไม่เห็น

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

  • onStop — เมธอดที่ถูกเรียกเมื่อ Activity สูญเสียการมองเห็นโดยสมบูรณ์ แต่ Activity ยังคงอยู่ในหน่วยความจำ
  • หลังจาก onStop Activity จะเปลี่ยนไปยังสถานะ Stopped — ยังคงอยู่ในหน่วยความจำ แต่ไม่ปรากฏและไม่โต้ตอบกับผู้ใช้
  • ระบบสามารถเรียก onRestart → onStart → onResume เมื่อกลับไปยัง Activity หรือ onDestroy เมื่อสิ้นสุด
  • ใน onStop จำเป็นต้องปล่อยทรัพยากร: หยุดแอนิเมชัน ปิดการใช้งานเซนเซอร์และกล้อง บันทึกข้อมูลชั่วคราว
  • การใช้งาน onStop อย่างถูกต้องเป็นปัจจัยสำคัญต่อความเสถียรของแอปพลิเคชันระหว่างการทำงานหลายอย่างพร้อมกันและการย่อ

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

onStop — เมธอด callback ของคลาส AppCompatActivity (และคลาส Activity ดั้งเดิม) ซึ่งถูกเรียกโดยระบบปฏิบัติการ Android เมื่อ Activity หยุดปรากฏอย่างสมบูรณ์แก่ผู้ใช้ ในขณะนี้ Activity ถูกซ่อนโดย Activity อื่น หน้าต่างโต้ตอบ ตัวเรียกใช้งานระบบ หรือหน้าจอล็อก จากมุมมองของวงจรชีวิต onStop ตามหลัง onPause และส่งสัญญาณว่า Activity ไม่ปรากฏบนหน้าจออีกต่อไป แม้ว่าวัตถุ Activity และสถานะของมันจะยังคงอยู่ในหน่วยความจำ

เมื่อ Activity เปลี่ยนไปยังสถานะ Stopped (หยุดแล้ว) มันจะคงสถานะไว้ใน RAM — ฟิลด์ทั้งหมด ลำดับชั้น View และ ViewModel ยังคงเข้าถึงได้ ซึ่งแยกความแตกต่างของ Stopped จากสถานะ Destroyed (ถูกทำลาย) ซึ่ง Activity จะถูกลบออกอย่างสมบูรณ์ UI ของระบบสามารถฆ่ากระบวนการของแอปพลิเคชันในสถานะ Stopped เมื่อหน่วยความจำไม่เพียงพอ — นี้เรียกว่า กระบวนการตาย นักพัฒนาต้องบันทึกข้อมูลสำคัญ (ร่าง ตำแหน่งเลื่อน) ใน onSaveInstanceState() ซึ่งถูกเรียกก่อน onStop เพื่อรับประกันการกู้คืนเมื่อกระบวนการตาย

ตามเอกสารคำจำกัดความความเข้ากันได้ของ Android (CDD) สำหรับเวอร์ชัน 14+ กระบวนการในสถานะ Stopped มีลำดับความสำคัญต่ำกว่าสำหรับการถูกฆ่าโดย OOM Killer — ต่ำกว่ากระบวนการในเฟสพื้นหลัง แต่สูงกว่ากระบวนการในแคช ตามสถิติของ Google 68% ของกรณีกระบวนการตายเกิดขึ้นเมื่อ Activity อยู่ในสถานะ Stopped ไม่ใช่ Paused

เมื่อใดที่ onStop ถูกเรียก: สถานการณ์และลำดับ

onStop ถูกเรียกเมื่อ Activity สูญเสียการมองเห็นโดยสมบูรณ์ ไม่ว่าจะด้วยสาเหตุใดก็ตาม: เริ่ม Activity ใหม่ทับ Activity ปัจจุบัน ย่อแอปพลิเคชัน (กด Home) ล็อกหน้าจอ สายเรียกเข้า หรือเปิดโต้ตอบระบบ ในทุกกรณีเหล่านี้ Activity จะได้รับ onPause (สูญเสียโฟกัสบางส่วน) ก่อน แล้วจึง onStop (สูญเสียการมองเห็นโดยสมบูรณ์)

สถานการณ์หลักของการเรียก onStop:

  • เริ่ม Activity ใหม่ทับ Activity ปัจจุบัน — Activity ปัจจุบันได้รับ onPause แล้ว onStop; Activity ใหม่ผ่าน onCreate → onStart → onResume
  • ย่อแอปพลิเคชัน (Home) — Activity เปลี่ยนเป็น onPause → onStop ภายใน 200–300 มิลลิวินาที คงอยู่ในหน่วยความจำในสถานะ Stopped
  • ล็อกหน้าจอ — ระบบเรียก onPause → onStop เพราะหน้าจอล็อกครอบคลุม Activity อย่างสมบูรณ์
  • สายเรียกเข้า — แอปพลิเคชันโทรศัพท์ (Dialer) เริ่มทำงานทับ Activity ปัจจุบันเปลี่ยนเป็น onStop
  • สลับไปยังแอปพลิเคชันอื่น (แอปล่าสุด) — Activity ถูกซ่อน ได้รับ onStop แต่ยังคงอยู่ในแคชกระบวนการ

สิ่งสำคัญที่ต้องเข้าใจคือ onStop จะไม่ถูกเรียก เมื่อหมุนหน้าจอ — ในกรณีนี้ Activity จะถูกทำลาย (onPause → onStop → onDestroy) และสร้างใหม่ (onCreate → onStart → onResume) ข้อยกเว้นคือแฟล็ก android:configChanges="orientation" ใน Manifest ซึ่งป้องกันการสร้าง Activity ใหม่และเรียก onConfigurationChanged() แทน

onStop ในวงจรชีวิต Activity

onStop อยู่ในตำแหน่งศูนย์กลางในลำดับวงจรชีวิต Activity ระหว่างสถานะที่มองเห็นและมองไม่เห็น ลำดับสมบูรณ์: onCreate → onStart → onResume → (สถานะทำงาน) → onPause → onStop → onDestroy (หรือ onRestart → onStart → onResume เมื่อกลับมา)

สถานะเมธอดการมองเห็นการโต้ตอบหน่วยความจำ
CreatedonCreateไม่ไม่จัดสรร
StartedonStartบางส่วนไม่เต็ม
ResumedonResumeเต็มใช่เต็ม
PausedonPauseบางส่วนไม่เต็ม
StoppedonStopไม่ไม่เต็ม*
DestroyedonDestroyไม่ไม่ถูกปล่อย

*ในสถานะ Stopped Activity จะถูกเก็บไว้ในหน่วยความจำแต่อาจถูกฆ่าโดยระบบเมื่อทรัพยากรไม่เพียงพอ ลำดับความสำคัญของการฆ่ากระบวนการ Stopped คือ รองสุดท้าย เหนือกว่ากระบวนการว่างในแคชเท่านั้น

onStop และ onSaveInstanceState: ระบบเรียก onSaveInstanceState(Bundle) ก่อน onStop เพื่อบันทึกสถานะ UI แบบไดนามิก นักพัฒนาสามารถ Override เมธอดนี้เพื่อบันทึกค่าฟิลด์อินพุต ตำแหน่ง RecyclerView และรายการที่เลือกใน Bundle แม้ว่า Activity จะไม่ถูกทำลาย (ผู้ใช้เพียงย่อและกลับมา) Bundle จะถูกส่งไปยัง onCreate เมื่อมีการเปลี่ยนแปลงการกำหนดค่า Google แนะนำให้บันทึกเฉพาะสถานะ UI ชั่วคราว — ไม่ใช่ข้อมูล Repository หรือ ViewModel ซึ่งอยู่ภายนอก Activity

ทรัพยากรใดที่ต้องปล่อยใน onStop

ใน onStop นักพัฒนาต้องปล่อยทรัพยากรทั้งหมดที่ไม่จำเป็นเมื่อ Activity ไม่ปรากฏ ซึ่งช่วยลดภาระแบตเตอรี่ CPU และหน่วยความจำ และยังป้องกัน ANR เมื่อกลับไปยัง Activity

สิ่งที่ต้องปล่อยใน onStop:

  • แอนิเมชันและการเปลี่ยนภาพ — หยุด ObjectAnimator, ValueAnimator, ViewPropertyAnimator แอนิเมชันที่ทำงานบน Activity ที่มองไม่เห็นเป็นการสิ้นเปลืองรอบ GPU
  • เซนเซอร์ — ยกเลิกการสมัครจาก SensorManager (มาตรความเร่ง, ไจโรสโคป, มาตรความเข้มสนามแม่เหล็ก) เซนเซอร์ใช้พลังงานแม้ว่า Activity จะถูกซ่อน
  • กล้องและไมโครโฟน — ปล่อย Camera2 หรือ CameraX หยุด MediaRecorder การปล่อยให้กล้องทำงานขณะที่ Activity ถูกซ่อนเป็นสิ่งต้องห้ามตามนโยบาย Google Play
  • LocationListener — ยกเลิกการสมัครจาก FusedLocationProviderClient หรือ LocationManager การระบุตำแหน่งทางภูมิศาสตร์เป็นทรัพยากรที่ใช้พลังงานมากที่สุด
  • ตัวฟังเครือข่าย — ปิด WebSocket ยกเลิกคำขอ HTTP ที่ไม่จำเป็นในเบื้องหลัง
  • MediaPlayer และ ExoPlayer — หยุดชั่วคราวหรือหยุดการเล่นหากไม่ควรดำเนินต่อในเบื้องหลัง

สิ่งที่ไม่ควรทำใน onStop: อย่าดำเนินการที่ใช้เวลานาน — บันทึกข้อมูลจำนวนมากในฐานข้อมูล คำขอเครือข่าย การคำนวณที่ซับซ้อน onStop ทำงานบนเธรดหลักและขัดขวางการกลับไปยัง Activity สำหรับการดำเนินการที่ใช้เวลานาน ให้ใช้ WorkManager กับความล่าช้าหรือ Coroutine ใน viewModelScope อย่าปล่อยทรัพยากร ViewModel — ViewModel อยู่รอดหลังจาก onStop และจะถูกใช้เมื่อกลับมา

ความแตกต่างระหว่าง onStop และ onPause

onPause และ onStop แตกต่างกันในระดับของการสูญเสียการมองเห็น และขอบเขตของการดำเนินการที่จำเป็น onPause ถูกเรียกเมื่อสูญเสียโฟกัสบางส่วน (เช่น การเปิดหน้าต่างโต้ตอบหรือเมนูระบบ) onStop — เมื่อสูญเสียการมองเห็นโดยสมบูรณ์ ความแตกต่างนี้สำคัญสำหรับการเลือกทรัพยากรที่จะปล่อยในแต่ละขั้นตอน

คุณลักษณะonPauseonStop
ระดับการมองเห็นมองเห็นได้บางส่วนมองไม่เห็นโดยสมบูรณ์
โฟกัสสูญเสียสูญเสีย
เวลาดำเนินการสูงสุด 500 มิลลิวินาทีสูงสุด 5 วินาที (หมดเวลา ANR)
ทรัพยากรที่ต้องปล่อยสำคัญ (สื่อ, กล้อง)ทั้งหมดที่มองไม่เห็น (เซนเซอร์, แอนิเมชัน, ตำแหน่ง)
การกู้คืนonResumeonRestart → onStart → onResume
ลำดับความสำคัญของกระบวนการสูง (เบื้องหน้า)ปานกลาง (เบื้องหลัง)

กฎทั่วไป: ใน onPause ให้ปล่อยทรัพยากรระบบที่ ส่งผลทันที ต่อประสบการณ์ผู้ใช้ของแอปพลิเคชันอื่น (กล้อง, เครื่องเล่นสื่อ); ใน onStop — ทรัพยากรอื่นทั้งหมดที่ไม่จำเป็นเมื่อ Activity ถูกซ่อน Google แนะนำให้บันทึกข้อมูลผู้ใช้ที่สำคัญ (ร่างอีเมล, การตั้งค่า) ใน onPause เนื่องจาก onStop อาจไม่ถูกเรียกระหว่างการสลับอย่างรวดเร็ว

onStop → onRestart: การกลับไปยังหน้าจอ

เมื่อผู้ใช้กลับไปยัง Activity ที่ถูกซ่อน ระบบจะเรียก onRestart → onStart → onResume เมธอด onRestart ส่งสัญญาณว่า Activity กำลังกลับมาจากสถานะ Stopped นี่เป็นขั้นตอนสำคัญสำหรับการกู้คืน UI และทรัพยากรที่ถูกปล่อยใน onStop

ลำดับการเรียกเมื่อกลับมา:

  • onRestart() — Activity ได้รับแจ้งว่าจะถูกแสดงอีกครั้ง การดำเนินการทั่วไป: โหลดข้อมูลใหม่ อัปเดตรายการ
  • onStart() — Activity ปรากฏขึ้นแต่ยังไม่ทำงาน ที่นี่ทรัพยากรที่ถูกปล่อยใน onStop จะถูกเริ่มต้นใหม่
  • onResume() — Activity ได้รับโฟกัสและพร้อมสำหรับการโต้ตอบ แอนิเมชันเริ่มทำงาน เซนเซอร์ถูกลงทะเบียน

หากกระบวนการของแอปพลิเคชันถูกฆ่าโดยระบบในสถานะ Stopped onCreate จะถูกเรียกแทน onRestart และ Bundle จาก onSaveInstanceState จะถูกส่งสำหรับการกู้คืนสถานะ สถานการณ์นี้ (กระบวนการตาย) เป็นหนึ่งในสาเหตุที่พบบ่อยที่สุดของบั๊กในแอปพลิเคชัน Android: นักพัฒนาดำเนินการ onRestart แต่ลืมพิจารณาการกู้คืนผ่าน onCreate หลังจากกระบวนการตาย

ตัวอย่างโค้ดกับ onStop ใน Kotlin

ตัวอย่างที่ 1: การใช้งาน onStop พื้นฐานกับการปล่อยเซนเซอร์

แสดงการยกเลิกการสมัครเซนเซอร์ที่ถูกต้องและการหยุดแอนิเมชันเมื่อซ่อน Activity เมื่อกลับไปยังหน้าจอ ทรัพยากรจะถูกกู้คืนใน onStart

kotlin
class MainActivity : AppCompatActivity() {
    private lateinit var sensorManager: SensorManager
    private var accelerometer: Sensor? = null
    private var rotationAnimator: ObjectAnimator? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    }

    override fun onStart() {
        super.onStart()
        accelerometer?.let {
            sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
        }
        rotationAnimator = ObjectAnimator.ofFloat(findViewById(R.id.icon), "rotation", 0f, 360f)
        rotationAnimator?.apply {
            duration = 3000
            repeatMode = ValueAnimator.RESTART
            repeatCount = ValueAnimator.INFINITE
            start()
        }
    }

    override fun onStop() {
        super.onStop()
        sensorManager.unregisterListener(sensorListener)
        rotationAnimator?.cancel()
    }

    override fun onRestart() {
        super.onRestart()
        Log.d("MainActivity", "Activity กำลังกลับมาจากสถานะ Stopped")
    }

    private val sensorListener = SensorEventListener { event, _ ->
        Log.d("MainActivity", "ความเร่ง: x=${event.values[0]}, y=${event.values[1]}, z=${event.values[2]}")
    }
}

โค้ดลงทะเบียนเซนเซอร์มาตรความเร่งและเริ่มแอนิเมชันหมุนไม่สิ้นสุดใน onStart ใน onStop เซนเซอร์ถูกยกเลิกการลงทะเบียนและแอนิเมชันถูกยกเลิก — ซึ่งป้องกันการใช้แบตเตอรี่เมื่อ Activity ถูกซ่อน หลังจากกลับผ่าน onRestart → onStart ทรัพยากรจะถูกสร้างใหม่

ตัวอย่างที่ 2: onStop กับการรักษาสถานะผ่าน SavedStateHandle

วิธีที่ทันสมัยโดยใช้ ViewModel + SavedStateHandle ข้อมูลฟอร์มจะถูกบันทึกโดยอัตโนมัติระหว่าง onStop โดยไม่ต้องจัดการ Bundle ด้วยตนเอง

kotlin
class FormViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    var email: String
        get() = savedStateHandle["email"] ?: ""
        set(value) { savedStateHandle["email"] = value }

    var message: String
        get() = savedStateHandle["message"] ?: ""
        set(value) { savedStateHandle["message"] = value }
}

class FormActivity : AppCompatActivity() {
    private val viewModel: FormViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_form)
        Log.d("FormActivity", "onCreate: email=${viewModel.email}")
    }

    override fun onStop() {
        super.onStop()
        Log.d("FormActivity", "onStop: ข้อมูลถูกบันทึกใน SavedStateHandle")
    }
}

SavedStateHandle จะบันทึกค่าใน Bundle โดยอัตโนมัติระหว่าง onSaveInstanceState ซึ่งถูกเรียกก่อน onStop เมื่อหมุนหน้าจอหรือกระบวนการตาย ข้อมูลจะถูกกู้คืนโดยไม่สูญเสีย Google แนะนำ SavedStateHandle สำหรับฟอร์มและร่างแทนการใช้ onSaveInstanceState โดยตรง

ตัวอย่างที่ 3: lifecycleScope สำหรับการดำเนินการใน onStop

การใช้ lifecycleScope กับ Coroutine สำหรับการบันทึกข้อมูลแบบอะซิงโครนัสระหว่างการเปลี่ยนไปยัง onStop Coroutine ทำงานบนตัวจัดส่ง IO โดยไม่บล็อกเธรดหลัก

kotlin
class NoteActivity : AppCompatActivity() {
    private val noteRepository = NoteRepository()

    override fun onStop() {
        lifecycleScope.launch(Dispatchers.IO) {
            val text = findViewById<EditText>(R.id.note_content).text.toString()
            noteRepository.saveDraft(text)
            withContext(Dispatchers.Main) {
                Log.d("NoteActivity", "ร่างถูกบันทึกใน onStop")
            }
        }
        super.onStop()
    }
}

Coroutine lifecycleScope.launch จะถูกยกเลิกโดยอัตโนมัติหากวงจรชีวิตของ Activity สิ้นสุดลง การใช้ Dispatchers.IO ช่วยให้แน่ใจว่าการเขียนฐานข้อมูลหรือไฟล์ไม่ขัดขวางการกลับไปยัง Activity ตามข้อมูลของ Google Coroutine ใน lifecycleScope เป็นวิธีที่ต้องการสำหรับการดำเนินการแบบอะซิงโครนัสใน onStop

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

onStop แตกต่างจาก onDestroy อย่างไร?

onStop — Activity หยุดปรากฏแต่ยังคงอยู่ในหน่วยความจำในสถานะ Stopped ระบบสามารถนำ Activity กลับผ่าน onRestart onDestroy — Activity ถูกทำลาย หน่วยความจำถูกปล่อย หลังจาก onDestroy การกลับมาทำได้โดยการสร้างอินสแตนซ์ Activity ใหม่ (onCreate) เท่านั้น

จำเป็นต้องเรียก super.onStop() หรือไม่?

ใช่ จำเป็น super.onStop() ช่วยให้มั่นใจว่าส่วนประกอบของระบบทำงานถูกต้อง: Fragment, LoaderManager, ViewModelStore การข้าม super.onStop() อาจทำให้หน่วยความจำรั่วและการกู้คืน Fragment ไม่ถูกต้อง ให้เรียก super.onStop() เสมอเป็นลำดับสุดท้ายหรือลำดับแรก — ลำดับไม่สำคัญ แต่การเรียกเป็นสิ่งจำเป็น

จะตรวจสอบว่า onStop ถูกเรียกแล้วได้อย่างไร?

ใช้ Log.d หรือ Timber ในแต่ละเมธอดของวงจรชีวิต เปิดใช้งานตัวกรอง logcat ตามแท็ก Activity ของคุณ สำหรับการผลิต ใช้ Android Vitals — Google รวบรวมเมตริกวงจรชีวิตโดยอัตโนมัติและแสดงความผิดปกติใน Play Console การตรวจสอบวงจรชีวิตยังสามารถใช้ผ่าน ProcessLifecycleOwner

จะเกิดอะไรขึ้นหากมีการโยนข้อยกเว้นใน onStop?

ข้อยกเว้นที่ไม่ถูกจับใน onStop ทำให้เกิด Force Close ของแอปพลิเคชัน ระบบไม่จับข้อยกเว้นใน Callback วงจรชีวิต หากใน onStop มีการดำเนินการที่อาจโยนข้อยกเว้น (การดำเนินการไฟล์, เครือข่าย) ให้ครอบคลุมใน try-catch และบันทึกข้อผิดพลาดโดยไม่ขัดจังหวะการทำงานของ super.onStop()

จำเป็นต้องปล่อย Bitmap ใน onStop หรือไม่?

ไม่ Bitmap ใน Activity จะถูกเก็บโดย GC หากไม่มีข้อมูลอ้างอิงถึงมัน การปล่อยแบบบังคับ (recycle()) ใน onStop ไม่จำเป็นและอาจเป็นอันตราย — หาก Activity กลับผ่าน onRestart จะต้องโหลด Bitmap ใหม่ ใช้ Glide หรือ Coil สำหรับการโหลดรูปภาพ — ไลบรารีเหล่านี้จัดการแคชและวงจรชีวิตโดยอัตโนมัติ

สรุป

  • onStop — เมธอดวงจรชีวิต Activity ที่ถูกเรียกเมื่อสูญเสียการมองเห็นโดยสมบูรณ์ Activity ยังคงอยู่ในหน่วยความจำในสถานะ Stopped
  • หลังจาก onStop มีสองสถานการณ์ที่เป็นไปได้: onRestart (กลับไปยังหน้าจอ) หรือ onDestroy (การทำลาย Activity)
  • ใน onStop คุณต้องปล่อยเซนเซอร์ แอนิเมชัน กล้อง ตัวฟังตำแหน่ง — ทุกอย่างที่ไม่จำเป็นเมื่อ Activity มองไม่เห็น
  • onStop แตกต่างจาก onPause ในระดับการมองเห็น: onPause — สูญเสียบางส่วน, onStop — สูญเสียการมองเห็นโดยสมบูรณ์
  • onSaveInstanceState ถูกเรียกก่อน onStop — ใช้เพื่อบันทึกสถานะ UI ชั่วคราว
  • Coroutine lifecycleScope กับ Dispatchers.IO — วิธีที่ต้องการสำหรับการดำเนินการแบบอะซิงโครนัสใน onStop
  • เรียก super.onStop() เสมอและครอบคลุมการดำเนินการอันตรายใน try-catch เพื่อหลีกเลี่ยง Force Close

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

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

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

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