ถึงแม้ว่านักพัฒนาจะเขียนโค้ดที่มี Syntax ถูกต้องแล้ว แต่ก็ไม่ได้หมายความว่าโค้ดเหล่านั้นจะทำงานได้ถูกต้องเสมอไป เพราะมีโอกาสที่โค้ดเหล่านี้จะทำงานผิดพลาดในระหว่างที่แอปกำลังทำงาน หรือที่เรียกกันว่า Runtime Error นั่นเอง
โดยระบบปฏิบัติการณ์จะบันทึก Log สำหรับการทำงานทั้งหมดภายในเครื่องอยู่ตลอดเวลา ซึ่งรวมไปถึง Log ที่เกิดขึ้นจาก Runtime Error ด้วยเช่นกัน และนักพัฒนาก็สามารถใช้เครื่องมือบน Android Studio ที่เรียกว่า Logcat เพื่อช่วยให้อ่าน Log จากอุปกรณ์แอนดรอยด์ได้ง่ายขึ้น
นั่นจึงทำให้ Logcat นั้นเป็นเครื่องมือพื้นฐานอันดับต้น ๆ ใน Android Studio ที่นักพัฒนาควรฝึกใช้งาน เพราะจะช่วยให้นักพัฒนาวิเคราะห์ปัญหาและตรวจสอบการทำงานของโค้ดในระหว่างที่แอปกำลังทำงานอยู่
ตั้งค่าอุปกรณ์แอนดรอยด์เพื่อใช้ Logcat
ถ้านักพัฒนาใช้ Virtual Device อย่าง Android Emulator มักจะไม่ต้องทำอะไรในขั้นตอนนี้ แต่ถ้าใช้ Physical Device หรืออุปกรณ์แอนดรอยด์ของจริงก็จะต้องทำขั้นตอนเหล่านี้ให้เรียบร้อยก่อน
- เปิด Developer options
- เปิดใช้งาน USB debugging ที่อยู่ใน Developer options
- เชื่อมต่ออุปกรณ์แอนดรอยด์เข้ากับคอมพิวเตอร์
นั่นก็เพราะว่าการทำงานของ Logcat จะใช้ความสามารถของ ADB หรือ Android Debug Bridge ที่ต้องเปิดใช้งานจากเมนู USB debugging ใน Developer options นั่นเอง
Logcat อยู่ตรงไหนของ Android Studio ?
ใน Android Studio เวอร์ชันล่าสุด Logcat จะอยู่ที่ซ้ายล่างของหน้าต่างโปรแกรม โดยสังเกตได้จากไอคอนตามภาพตัวอย่างข้างล่าง
เมื่อกดเปิดเมนู Logcat ขึ้นมา ก็จะเห็นหน้าต่างแสดงขึ้นมาประมาณนี้
ซึ่งข้อมูลที่แสดงอยู่ในหน้าต่างดังกล่าวคือ Log ที่มาจากอุปกรณ์แอนดรอยด์ที่เชื่อมต่ออยู่นั่นเอง
ถ้า Log ไม่แสดงใน Logcat อาจจะเป็นเพราะอุปกรณ์แอนดรอยด์ยังไม่ได้เชื่อมต่อกับคอมพิวเตอร์ผ่าน ADB
การใช้งาน Logcat บนแอนดรอยด์
Logcat จะช่วยให้นักพัฒนาดู Log จากการทำงานของอุปกรณ์แอนดรอยด์ได้ง่ายขึ้น เช่น สถานะของข้อมูลบางอย่างภายในโค้ด, การรับส่งข้อมูลระหว่างตัวเครื่องกับ Web Service, หรือการทำงานของ OS เอง เป็นต้น ซึ่ง Log เหล่านี้จะมาจากโค้ดที่นักพัฒนาแอปต่าง ๆ ใส่ไว้นั่นเอง
โดยในปัจจุบัน Logcat เป็นเวอร์ชัน 2 แล้ว และมีรูปแบบแตกต่างไปจากเวอร์ชันเก่าพอสมควร โดยเจ้าของบล็อกเขียนแยกไว้เป็นบทความการใช้งาน Logcat v2 บน Android Studio ลองตามไปอ่านกันได้ว่าใช้งานยังไง
การแสดง Log บนแอนดรอยด์
นักพัฒนาสามารถใช้คลาส Log (android.util.Log
) เพื่อให้แอปส่งข้อมูลออกไปที่ Log ได้ โดยจะมีรูปแบบการเรียกใช้งานแบบนี้
Log.v("Tag", "Message")
Log.d("Tag", "Message")
Log.i("Tag", "Message")
Log.w("Tag", "Message")
Log.e("Tag", "Message")
Log.wtf("Tag", "Message")
คำสั่ง Log ทุกตัวจะประกอบไปด้วย Parameter หลักๆ 2 ตัวด้วยกันคือ Tag และ Message ที่เป็น String ทั้งคู่
- Tag คือหัวข้อกำกับของ Log นั้นๆ กำหนดเป็นอะไรก็ได้ไม่มีข้อจำกัดตายตัว
- Message คือข้อความของ Log นั้นๆ กำหนดเป็นอะไรก็ได้เช่นกัน ไม่ต่างจาก Tag
นักพัฒนาจะต้องเป็นคนกำหนดเองว่าจะให้แสดงข้อความอะไร ซึ่ง Tag จะนิยมกำหนดเป็นหัวข้อของ Log นั้นๆ ส่วน Message ก็คือข้อความและข้อมูลการทำงานของโค้ดที่อยากจะให้แสดงออกมา
ตัวอย่างการใช้คำสั่ง Log
จุดประสงค์ของการใช้คำสั่ง Log คือ “อยากจะรู้อะไร ก็ให้แสดงมันออกมาซะ” ดังนั้นจึงไม่มีการกำหนดรูปแบบตายตัวว่าจะต้องแสดงอะไรใน Logcat
ยกตัวอย่างเช่น
// MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
/* ... */
Log.d("Awesome Tag", "Very useful message")
}
}
เมื่อแอปทำงานก็จะเห็น Log ตัวนี้โผล่ขึ้นมาใน Logcat ทันที
โดย Log ที่แสดงใน Logcat จะประกอบไปด้วย
ประเภทของ Log
นอกจากการใช้ Log จะช่วยแสดงข้อมูลที่ต้องการแล้ว Log ยังถูกแบ่งออกเป็นหลายประเภทเพื่อให้นักพัฒนาสามารถแยกประเภทของ Log ให้เหมาะสมกับแต่ละกรณีได้มากขึ้น
โดย Log จะถูกแบ่งออกเป็น 5 ประเภทดังนี้
- Verbose (V) ใช้แสดงข้อความที่ไม่ค่อยสำคัญมากนัก
- Debug (D) ใช้แสดงข้อความสำหรับการ Debug
- Info (I) ใช้แสดงข้อความสำหรับแสดงข้อมูลการทำงานบางอย่าง
- Warning (W) ใช้แสดงข้อผิดพลาดในการทำงานของโค้ดที่ไม่ร้ายแรง (แค่เตือน)
- Error (E) ใช้แสดงข้อผิดพลาดในการทำงานของโค้ด
และนักพัฒนายังสามารถเปลี่ยนสีของ Log แต่ละประเภทเพื่อช่วยให้ดูได้ง่ายขึ้นได้อีกด้วย
Logcat แสดงสาเหตุของปัญหาให้ทุกครั้งที่ Force Close (แอปพัง)
ถ้ามั่นใจว่าเขียนโค้ดถูกต้อง (อย่างน้อยก็ Syntax ถูก) แต่เมื่อลองใช้งานแอปไปได้ซักพักก็เจอปัญหาว่าแอปปิดตัวลง ซึ่งเป็นเรื่องปกติที่นักพัฒนาแอนดรอยด์ทุกคนจะได้เจอ ซึ่งปัญหานี้เกิดมาจาก Runtime Error จนทำให้เกิด Force Close หรือแอปพังจนปิดตัวเองนั่นเอง
เมื่อเกิดปัญหาแบบนี้ สิ่งสำคัญที่นักพัฒนาจะต้องรู้ให้ได้เลยก็คือ "ปัญหาเกิดมาจากอะไร" โดยใช้ Logcat เพื่อดู Error Log ที่เกิดขึ้น ณ ตอนนั้น
ภาพตัวอย่างข้างบนคือ Error Log ที่แสดงใน Logcat ตอนที่แอปพัง ซึ่งข้อความเหล่านี้จะบอกปัญหาที่ทำให้แอปถูก Force Close นั่นเอง อีกทั้งยังบอกให้ด้วยว่าโค้ดบรรทัดไหนในไฟล์ไหนที่ทำให้เกิดปัญหาดังกล่าว
จากตัวอย่างจะเห็นว่าปัญหาคือ NullPointerException
ที่เกิดขึ้นใน MainActivity.kt
บรรทัดที่ 43 โดยสามารถกดที่ตัวหนังสือสีน้ำเงินดังกล่าวเพื่อไปที่ไฟล์ดังกล่าวได้ในทันที เพื่อวิเคราะห์ปัญหาต่อไปว่าเกิดจากอะไร และทำการแก้ไขให้เรียบร้อย
ปกติใช้ Logcat ทำอะไรกันบ้าง?
Logcat เป็นเครื่องมือที่ทรงพลังมากสำหรับนักพัฒนาแอนดรอยด์ ดังนั้นเรามาดูกันว่าส่วนใหญ่เราใช้ Logcat ทำอะไรกัน
ศึกษาหรือตรวจสอบการทำงานของโค้ด
เมื่อใดที่อยากรู้ว่าโค้ดตรงไหนทำงานก่อนหรือหลัง และโค้ดตรงไหนถูกเรียกบ้าง ก็ให้ลองใส่คำสั่ง Log ลงไปตรง ๆ ได้เลย แล้วตอนที่แอปทำงานก็จะเห็น Log เหล่านั้นจาก Logcat
ยกตัวอย่างเช่น ต้องการรู้ลำดับการทำงานของ Activity Lifecycle
// MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
/* ... */
Log.d("MainActivity", "onCreate")
}
override fun onStart() {
/* ... */
Log.d("MainActivity", "onStart")
}
override fun onResume() {
/* ... */
Log.d("MainActivity", "onResume")
}
override fun onPause() {
/* ... */
Log.d("MainActivity", "onPause")
}
override fun onStop() {
/* ... */
Log.d("MainActivity", "onStop")
}
override fun onDestroy() {
/* ... */
Log.d("MainActivity", "onDestroy")
}
override fun onRestart() {
/* ... */
Log.d("MainActivity", "onRestart")
}
}
ตรวจสอบ Fatal Error หรือ Runtime Exception
จากที่อธิบายไปก่อนหน้านี้ว่าเวลาที่แอปมีปัญหาแล้ว Force Close การใช้ Logcat จะช่วยแสดง Error Log ที่เกี่ยวข้องออกมาเพื่อช่วยให้นักพัฒนาตรวจสอบปัญหาได้ง่ายขึ้น และถ้าอ่านแล้วยังไม่เข้าใจ ก็สามารถเอาไปถามหรือค้นหาต่อในอินเตอร์เน็ตได้
ตรวจสอบเงื่อนไขหรือค่าต่าง ๆ ในโค้ด
เมื่อมีการเขียนโค้ดที่ทำงานตามเงื่อนไขแล้วไม่รู้ว่าโค้ดส่วนไหนถูกเรียกตอนที่แอปทำงาน หรืออยากรู้ค่าที่อยู่ในตัวแปร นอกจากจะใช้เครื่องมืออย่าง Debugger ก็สามารถใช้ Log เพื่อแสดงข้อมูลเหล่านั้นออกมาได้เช่นกัน
fun onTouchEvent(event: MotionEvent): Boolean {
Log.d("Touch Event", "Position : ${event.x}, ${event.y}")
when (event.action) {
MotionEvent.ACTION_DOWN -> Log.d("Touch Event", "Action Down")
MotionEvent.ACTION_MOVE -> Log.d("Touch Event", "Action Move")
MotionEvent.ACTION_UP -> Log.d("Touch Event", "Action Up")
}
return true
}
Logcat มีไว้ให้คนอ่าน จงทำให้มันเข้าใจง่าย
การแสดงข้อความใดๆผ่านคำสั่ง Log ทุกครั้ง ควรเป็นข้อความที่ “เข้าใจง่าย”, “ดูไม่ยาก” และ “ไม่ปนกันมั่ว” เพราะตัวเราเองนั่นแหละที่ต้องมานั่งดู Logcat
- อย่าแสดงแค่ตัวเลข แต่ไม่บอกว่ามันคืออะไร
- อย่าแสดงข้อความที่ไม่จำเป็น หรืออ่านแล้วไม่เข้าใจว่าจะสื่ออะไร
- แสดง Log ให้น้อยบรรทัดที่สุด
- พยายามทำให้ดูแล้วเข้าใจง่ายที่สุด
- แยกประเภทของ Log ให้ถูกต้อง
- ตอนทำเป็น Production ถ้ามี Log อันไหนไม่อยากให้แสดงก็อย่าลืมเอาออกด้วย
จัดการ Log อย่างมีประสิทธิภาพมากขึ้นด้วย Timber
Timber เป็น Library ที่จะช่วยให้นักพัฒนาสามารถจัดการ Log บนแอนดรอยด์ได้สะดวกขึ้น สามารถซ่อน Log ที่ไม่จำเป็นออกจาก Production Build ได้โดยไม่ต้องลบโค้ดเหล่านั้นออก
สรุป
Logcat เป็นเพียงแค่เครื่องมือช่วยอำนวยความสะดวกให้กับนักพัฒนาเท่านั้น ดังนั้นจึงมีสิ่งที่นักพัฒนาควรรู้เพื่อให้ใช้งาน Log ได้อย่างมีประสิทธิภาพและตอบโจทย์กับการพัฒนาแอปบนแอนดรอยด์มากขึ้น
- ควรใส่คำสั่งไว้ตรงไหน?
- ควรแสดงข้อมูลอะไร?
- วิเคราะห์ปัญหาจาก Error Log
ดังนั้น Logcat จึงเป็นเครื่องมือที่นักพัฒนาควรฝึกใช้งานให้ชำนาญ เพราะไม่ว่าจะพัฒนาแอปบนแอนดรอยด์เชี่ยวชาญแค่ไหน สุดท้ายก็ยังต้องพึ่งเจ้าเครื่องมือตัวนี้อยู่ดี
และสุดท้ายนี้ก็ขอกล่าวจบท้ายบทความนี้ไว้ว่า
“ชนใดไม่เคยใช้ Logcat แปลว่าชนนั้นไม่เคยเขียนโค้ดแอนดรอยด์ด้วยตนเอง”