onCreate คือเมธอดแรกและเป็นเมธอดเดียวที่จำเป็นในวงจรชีวิต (lifecycle) ของ Activity และ Fragment ใน Android ระบบจะเรียกเมธอดนี้หนึ่งครั้งเมื่อสร้างคอมโพเนนต์ โดยส่งพารามิเตอร์ Bundle ที่เก็บสถานะที่บันทึกไว้ก่อนหน้านี้ ภายใน onCreate นักพัฒนาจะเริ่มต้นอินเทอร์เฟซผู้ใช้ ผูก View-อิลิเมนต์ ตั้งค่าแฮนเดิลเหตุการณ์ และกู้คืนข้อมูลจาก savedInstanceState หากไม่มีการใช้งาน onCreate อย่างถูกต้อง จะไม่สามารถรันแอปพลิเคชัน Android ใด ๆ ได้เลย — นี่คือจุดเริ่มต้นของทุกหน้าจอ อ่านเพิ่มเติมเกี่ยวกับวงจรชีวิตทั่วไปของ Activity ได้ในบทความ Activity Lifecycle
สิ่งสำคัญ
onCreate คือเมธอดเรียกกลับ (callback) ที่ Android เรียกเมื่อสร้างอินสแตนซ์ใหม่ของ Activity หรือ Fragment นี่คือจุดเข้าสู่โค้ดของหน้าจอผู้ใช้จุดแรก: ก่อนที่ onCreate จะถูกเรียก ไม่มีโค้ดของผู้ใช้ใดถูกทำงานเลย ระบบส่งพารามิเตอร์ Bundle ให้กับเมธอด ซึ่งอาจมีข้อมูลที่บันทึกไว้ก่อนหน้านี้ (เมื่อถูกสร้างใหม่) หรือมีค่าเท่ากับ null (เมื่อรันครั้งแรก)
เมธอด onCreate ถูกกำหนดไว้ในคลาส android.app.Activity และในคลาส androidx.fragment.app.Fragment ทั้งสองเวอร์ชันทำงานที่คล้ายกัน: การเริ่มต้นคอมโพเนนต์ การตั้งค่า UI และการกู้คืนสถานะ อย่างไรก็ตามการใช้งานจริงแตกต่างกัน — Activity ใช้ setContentView เพื่อโหลดเลย์เอาต์ ส่วน Fragment คืนค่า View ผ่าน onCreateView นักพัฒนาจำเป็นต้องโอเวอร์ไรด์อย่างน้อย onCreate ใน Activity — หากไม่มีสิ่งนี้ Android จะไม่สามารถแสดงหน้าจอได้
onCreate ถูกเรียกหนึ่งครั้งอย่างเคร่งครัดตลอดวงจรชีวิตทั้งหมดของอินสแตนซ์ Activity แม้เมื่อหมุนหน้าจอ อินสแตนซ์ใหม่ของ Activity ก็จะได้รับ onCreate อีกครั้งพร้อม Bundle จากอินสแตนซ์ก่อนหน้า คุณสมบัตินี้ทำให้ onCreate เป็นจุดที่เหมาะสำหรับการเริ่มต้นแบบครั้งเดียว: การโหลดข้อมูล การสร้างแอดแดปเตอร์ การตั้งค่าคอมโพเนนต์ DI ผ่าน Dagger หรือ Hilt
ใน Activity เมธอด onCreate ทำหน้าที่หลักสี่อย่าง: การโหลดเลย์เอาต์ (layout) การเริ่มต้น View-อิลิเมนต์ การกู้คืนสถานะจาก Bundle และการตั้งค่าแฮนเดิลเหตุการณ์เริ่มต้น โค้ดขั้นต่ำที่จำเป็นใน onCreate คือการเรียก super.onCreate(savedInstanceState) และ setContentView(R.layout.activity_main)
class MainActivity : AppCompatActivity() {
private var binding: ActivityMainBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ViewBinding — ตัวแทนที่ทันสมัยของ findViewById
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding?.root)
// การเริ่มต้นด้วย binding
binding?.apply {
welcomeText.text = getString(R.string.welcome)
startButton.setOnClickListener { startGame() }
}
// การกู้คืนสถานะ
if (savedInstanceState != null) {
score = savedInstanceState.getInt("score", 0)
binding?.scoreText?.text = score.toString()
}
}
}
แนวทางปฏิบัติสมัยใหม่คือการใช้ ViewBinding แทน findViewById ViewBinding จะสร้างคลาส ActivityMainBinding ในขั้นตอนการคอมไพล์ ซึ่งช่วยขจัดข้อผิดพลาดจาก ID ที่ไม่ถูกต้องและลดปริมาณโค้ดซ้ำ ๆ Google แนะนำให้ใช้ ViewBinding เป็นวิธีมาตรฐานในการเข้าถึง View ใน Activity และ Fragment ตั้งแต่ Android Studio 3.6 เป็นต้นไป
ลำดับการทำงานใน onCreate ต้องเข้มงวด: เรียก super ก่อน จากนั้น setContentView แล้วจึงทำอย่างอื่น การเรียก findViewById ก่อน setContentView จะคืนค่า null — เลย์เอาต์ยังไม่ถูกโหลด และ View-อิลิเมนต์ยังไม่มีอยู่ในลำดับชั้น นี่เป็นหนึ่งในข้อผิดพลาดที่พบบ่อยที่สุดของนักพัฒนา Android มือใหม่
onCreate ใน Fragment แตกต่างจาก Activity: ที่นี่ไม่มีการเรียก setContentView แต่ทำเพียงการเริ่มต้นข้อมูลที่ไม่เกี่ยวกับ UI Fragment แบ่งการสร้างคอมโพเนนต์และการสร้าง View ออกเป็นสองเมธอดแยกกัน: onCreate (ถูกเรียกหนึ่งครั้ง) และ onCreateView (ถูกเรียกทุกครั้งเมื่อสร้างหรือสร้าง View ใหม่)
class UserListFragment : Fragment() {
private lateinit var viewModel: UserViewModel
private var binding: FragmentUserListBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// การเริ่มต้น ViewModel — อยู่รอดผ่านการสร้าง View ใหม่
viewModel = ViewModelProvider(this)[UserViewModel::class.java]
// อาร์กิวเมนต์จาก FragmentManager
arguments?.let {
viewModel.loadUser(it.getString("user_id") ?: "")
}
// การบันทึกเมื่อหมุนหน้าจอ
retainInstance = true
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentUserListBinding.inflate(inflater, container, false)
return binding!!.root
}
}
ความแตกต่างสำคัญระหว่าง onCreate ของ Activity และ Fragment: onCreate ใน Fragment ไม่ควรมีโค้ดที่เกี่ยวข้องกับ View เพราะ View อาจถูกทำลายและสร้างขึ้นใหม่ได้ (เช่น เมื่อสลับแท็บใน ViewPager) ในขณะที่ onCreate ถูกเรียกเพียงครั้งเดียว การโหลดข้อมูล การตั้งค่า ViewModel และการเริ่มต้นแอดแดปเตอร์เป็นงานของ onCreate ส่วนการผูก View เป็นงานของ onViewCreated
พารามิเตอร์ savedInstanceState ใน onCreate เป็นกลไกสำหรับบันทึกและกู้คืนสถานะชั่วคราวของ Activity หรือ Fragment เมื่อระบบทำลาย Activity (หมุนหน้าจอ หน่วยความจำไม่เพียงพอ) ระบบจะเรียก onSaveInstanceState() ซึ่งนักพัฒนาใส่คู่คีย์-ค่า (key-value) ลงใน Bundle เมื่อสร้างอินสแตนซ์ใหม่ Bundle นี้จะถูกส่งกลับไปยัง onCreate
Bundle รองรับชนิดข้อมูลต่อไปนี้: String, Integer, Boolean, Long, Float, Double, อาร์เรย์ของมัน รวมถึงออบเจกต์ Parcelable และ Serializable สำหรับออบเจกต์ที่ซับซ้อนจะใช้ Parcelable ซึ่งเป็นกลไกการซีเรียลไลซ์ที่มีประสิทธิภาพสูงกว่าและเฉพาะของ Android ขนาดของ Bundle ถูกจำกัดไว้ประมาณ 500 กิโลไบต์ — การเกินขีดจำกัดจะทำให้เกิดข้อยกเว้น TransactionTooLargeException
companion object {
private const val KEY_USER_NAME = "user_name"
private const val KEY_SCORE = "score"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)
if (savedInstanceState != null) {
userName = savedInstanceState.getString(KEY_USER_NAME) ?: ""
currentScore = savedInstanceState.getInt(KEY_SCORE)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(KEY_USER_NAME, userName)
outState.putInt(KEY_SCORE, currentScore)
}
สิ่งสำคัญที่ต้องเข้าใจ: onSaveInstanceState จะไม่ถูกเรียกเมื่อผู้ใช้ปิด Activity อย่างชัดเจนผ่าน finish() หรือกดปุ่ม “ย้อนกลับ” ระบบถือว่าผู้ใช้จงใจสิ้นสุดการทำงาน และไม่จำเป็นต้องบันทึกสถานะ ดังนั้นจึงไม่ควรพึ่งพา savedInstanceState เพียงอย่างเดียวสำหรับการจัดเก็บข้อมูลระยะยาว — ให้ใช้ Room, DataStore หรือ SharedPreferences แทน
onCreate ทำงานบนเธรดหลัก (UI) และระบบจะรอให้มันเสร็จสิ้นก่อนจึงจะแสดง Activity บนหน้าจอ หาก onCreate ทำงานนานกว่า 5 วินาที ระบบจะแสดงกล่องโต้ตอบ ANR (Application Not Responding) และเสนอให้ผู้ใช้ปิดแอปพลิเคชัน งานที่ใช้เวลานาน เช่น การโหลดข้อมูลจากเครือข่ายหรือการอ่านจากฐานข้อมูล ควรย้ายไปยังเธรดเบื้องหลัง
ตามคำแนะนำของ Google Android Performance (2025) onCreate ควรเสร็จสิ้นภายในเวลา น้อยกว่า 1 วินาที บนอุปกรณ์ระดับกลาง เพื่อให้ได้ตามนี้ ควร: ใช้การเริ่มต้นแบบขี้เกียจ (lazy delegate ใน Kotlin) เลื่อนการโหลดข้อมูลหนักไปที่ onResume หรือผ่านคอรูทีน ใช้ ViewStub สำหรับ UI-คอมโพเนนต์ที่ไม่ค่อยได้ใช้ และโปรไฟล์เวลาสตาร์ทผ่าน Android Vitals
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// การเริ่มต้นแบบขี้เกียจ — ออบเจกต์ถูกสร้างเมื่อเข้าถึงครั้งแรกเท่านั้น
val heavyData by lazy {
HeavyDataLoader.load()
}
// การโหลดข้อมูลในเธรดเบื้องหลังผ่าน lifecycleScope
lifecycleScope.launch(Dispatchers.IO) {
val users = userDao.getAllUsers()
withContext(Dispatchers.Main) {
adapter.submitList(users)
}
}
}
เครื่องมือโปรไฟลิง: Android Studio Profiler (แท็บ CPU) แสดงเวลาการทำงานที่แม่นยำของแต่ละเมธอด ใน Android Vitals (คอนโซล Google Play) คุณสามารถติดตามเมตริก “เวลาสตาร์ทแบบเย็น” — หาก onCreate ของ Activity ของคุณเกิน 500 มิลลิวินาที คอนโซลจะระบุว่าเป็นปัญหาด้านประสิทธิภาพ เราที่ IT Sectr ใช้การทดสอบ Macrobenchmark เพื่อควบคุมเวลาสตาร์ทของแต่ละ Activity ใน CI-ไพพ์ไลน์โดยอัตโนมัติ
ViewModel เป็นวิธีที่ดีที่สุดในการเริ่มต้นข้อมูลใน onCreate ที่ต้องอยู่รอดผ่านการหมุนหน้าจอ ViewModel ถูกสร้างใน onCreate ผ่าน ViewModelProvider และจะถูกเก็บไว้โดยอัตโนมัติเมื่อมีการเปลี่ยนแปลงคอนฟิกูเรชัน เมื่อ Activity ถูกสร้างใหม่หลังการหมุนหน้าจอ ViewModel ยังคงอยู่ในหน่วยความจำ และ onCreate จะได้รับ ViewModel เดียวกันโดยไม่สูญเสียข้อมูล
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile)
// ViewModel ถูกสร้างหนึ่งครั้งและอยู่รอดผ่านการเปลี่ยนแปลงคอนฟิกูเรชัน
val viewModel: ProfileViewModel =
ViewModelProvider(this)[ProfileViewModel::class.java]
// การสังเกต LiveData — UI อัปเดตโดยอัตโนมัติเมื่อข้อมูลเปลี่ยนแปลง
viewModel.user.observe(this) { user ->
binding?.userName?.text = user.name
binding?.userEmail?.text = user.email
}
// การโหลดข้อมูล หาก ViewModel เพิ่งถูกสร้าง
if (savedInstanceState == null) {
viewModel.loadProfile(userId)
}
}
การผสมผสานระหว่าง ViewModel + LiveData/StateFlow แก้ปัญหาการหมุนหน้าจอโดยไม่ต้องบันทึกด้วยตนเองใน Bundle ViewModel เก็บข้อมูลในหน่วยความจำ LiveData จะสมัครรับข้อมูล Activity อีกครั้งโดยอัตโนมัติเมื่อถูกสร้างใหม่ ส่วน StateFlow (จาก Kotlin Coroutines) เพิ่มความสามารถแบบรีแอกทีฟพร้อมรองรับคอรูทีน นี่คือสถาปัตยกรรมมาตรฐานที่ Google แนะนำในคู่มือ Guide to App Architecture
แม้แต่นักพัฒนาที่มีประสบการณ์ก็ยังทำผิดพลาดทั่วไปใน onCreate มาดูปัญหาที่พบบ่อยที่สุดห้าปัญหาและวิธีหลีกเลี่ยง
ข้อผิดพลาดที่พบบ่อยที่สุดคือการพยายามค้นหา View ผ่าน findViewById ก่อนเรียก setContentView View-อิลิเมนต์ทั้งหมดจะถูกสร้างขึ้นในขณะที่อินเฟลตเลย์เอาต์ ดังนั้นการเข้าถึง findViewById ใด ๆ ก่อน setContentView จะคืนค่า null และทำให้เกิด NullPointerException เมื่อพยายามใช้ View วิธีแก้: ลำดับที่เข้มงวด — เรียก super ก่อน จากนั้น setContentView แล้วจึง findViewById หรือ ViewBinding
การโหลดข้อมูลจากเครือข่าย การอ่านจากฐานข้อมูล หรือการประมวลผลอาร์เรย์ขนาดใหญ่โดยตรงใน onCreate จะบล็อกการวาดเฟรมแรก ผู้ใช้จะเห็นหน้าจอดำจนกว่า onCreate จะเสร็จสิ้น ซึ่งทำให้การรับรู้ความเร็วของแอปพลิเคชันแย่ลง วิธีแก้: ใช้ lifecycleScope.launch สำหรับงานแบบอะซิงโครนัส และแสดงสเกเลตัน (placeholder UI) จนกว่าการโหลดจะเสร็จสิ้น
หากเมื่อหมุนหน้าจอแล้วไม่กู้คืนสถานะจาก Bundle ผู้ใช้จะสูญเสียอินพุตที่ยังไม่ได้บันทึกทั้งหมด: ข้อความในช่องฟอร์ม ตำแหน่งการเลื่อน และรายการที่เลือกไว้ วิธีแก้: ตรวจสอบ savedInstanceState != null ใน onCreate เสมอเพื่อกู้คืนข้อมูล แม้ดูเหมือนว่าการสูญเสียสถานะจะเกิดขึ้นได้ยาก
คลาสนิรนามและแลมบ์ดาใน onCreate อาจเก็บอ้างอิงของ Activity ไว้โดยไม่รู้ตัวแม้หลังถูกทำลายแล้ว ตัวอย่างเช่น Handler ที่สร้างใน onCreate ยังคงทำงานตามเวลาที่เลื่อนไว้แม้ Activity ถูกทำลายแล้ว วิธีแก้: ใช้ LifecycleObserver, ViewModel และ lifecycleScope ซึ่งจะยกเลิกงานโดยอัตโนมัติเมื่อถูกทำลาย
การเริ่มต้น View ใน onCreate ของ Fragment เป็นความผิดพลาดเชิงตรรกะ เนื่องจาก View อาจถูกสร้างใหม่โดยไม่มีการเรียก onCreate หากตั้งค่าลิสเนอร์ใน onCreate แล้วผูก View ใน onCreateView เมื่อมีการสร้างใหม่ ลิสเนอร์จะยังติดอยู่กับ View เก่า วิธีแก้: ทำงานกับ View ทั้งหมดใน onViewCreated และปล่อยให้ onCreate ใช้สำหรับการเริ่มต้นชั้นข้อมูลเท่านั้น
คำถามที่พบบ่อย
ใช่ การโอเวอร์ไรด์ onCreate จำเป็น สำหรับ Activity ใด ๆ ที่แสดงอินเทอร์เฟซผู้ใช้ หากไม่มีสิ่งนี้จะไม่สามารถเรียก setContentView และโหลด XML เลย์เอาต์ได้ หาก Activity ไม่มี UI (เช่น Activity ตัวแทนแบบโปร่งใส) ก็ยังต้องโอเวอร์ไรด์ onCreate แต่ไม่มีการเรียก setContentView
ไม่ onCreate ไม่สามารถถูกเรียกซ้ำสำหรับอินสแตนซ์เดียวกันของ Activity ได้ หาก Activity ถูกทำลายและถูกสร้างใหม่ (หมุนหน้าจอ หน่วยความจำไม่เพียงพอ) นี่คืออินสแตนซ์ใหม่พร้อมการเรียก onCreate ครั้งใหม่ ข้อยกเว้นคือเมธอด recreate() ซึ่งบังคับทำลายและสร้าง Activity ใหม่ แต่เป็นการสร้างอินสแตนซ์ใหม่
หากไม่เรียก super.onCreate(savedInstanceState) Android Runtime จะโยนข้อยกเว้น SuperNotCalledException และแอปพลิเคชันจะพัง ระบบกำหนดอย่างเคร่งครัดว่าเมธอดวงจรชีวิตที่ถูกโอเวอร์ไรด์ทุกเมธอดต้องเรียก super เวอร์ชันของตัวเอง — สิ่งนี้รับประกันการทำงานที่ถูกต้องของสถานะเครื่องกล (state machine) ภายใน
ความแตกต่างหลัก: onCreate ใน Activity โหลด UI ผ่าน setContentView ส่วน onCreate ใน Fragment เพียงเริ่มต้นข้อมูล Fragment สร้าง View ในเมธอดแยกชื่อ onCreateView ซึ่งสามารถถูกเรียกได้หลายครั้ง (เช่น เมื่อสลับแท็บ) ในขณะที่ onCreate ของ Fragment ถูกเรียกเพียงครั้งเดียวตลอดอายุของอินสแตนซ์ Fragment
ข้อมูลที่เริ่มต้นใน onCreate จะถูกเก็บไว้ในฟิลด์ของคลาส Activity หรือ Fragment ตัวอย่างเช่น private lateinit var binding: ActivityMainBinding ถูกประกาศในระดับคลาส เริ่มต้นใน onCreate และเข้าถึงได้ในทุกเมธอดที่ตามมา สำหรับข้อมูลที่ต้องอยู่รอดผ่านการหมุนหน้าจอ ให้ใช้ ViewModel ร่วมกับ LiveData หรือ StateFlow
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ