Timer และ TimerTask เป็นคลาสในไลบรารีมาตรฐานของภาษาจาวา ซึ่งในแอนดรอยด์ก็มีให้ใช้งานเช่นกัน (ไลบรารีในแอนดรอยด์นั้น บางส่วนจะดึงมาจากของจาวาตรงๆ บางส่วนเอาของจาวามาดัดแปลงวิธีใช้งาน และบางส่วนเป็นไลบรารีเฉพาะของแอนดรอยด์เอง)
สองคลาสนี้อยู่ในแพคเกจ java.util หน้าที่ของมันก็ตามชื่อแหละครับ คือเป็นไทเมอร์หรือตัวตั้งเวลาการทำงาน ที่ช่วยให้เราทำงานหนึ่ง ณ เวลาที่ต้องการ หรือทำงานหนึ่งซ้ำๆกันทุกช่วงเวลาที่ต้องการได้ เช่น ตั้งเวลาให้อ่านข้อมูลจากเซิร์ฟเวอร์ทุกๆ 10 นาที เป็นต้น
สาเหตุที่ผมเขียนบทความนี้ เนื่องจากมีผู้อ่านหนังสือของผมท่านหนึ่งถามมาว่า “ภายในหน้าเดียวกัน ถ้ามีภาพ 3 ภาพ และต้องการไม่ให้ภาพปรากฏพร้อมกันจะทำได้อย่างไร เช่น ภาพที่ 1 มาก่อน ต่อมาค่อยปรากฏภาพที่ 2 แล้วสุดท้ายค่อยปรากฏภาพที่ 3” ผมลองนึกๆดูและหาข้อมูลเพิ่มจากกูเกิล ก็พบว่ามีหลายวิธีที่น่าจะทำได้ และหนึ่งในนั้นก็คือการตั้งเวลาเปลี่ยนภาพใน ImageView โดยใช้ Timer ร่วมกับ TimerTask นี่แหละครับ
หลักการใช้งาน Timer และ TimerTask
วิธีใช้งาน Timer และ TimerTask ก่อนอื่นให้สร้างคลาสใหม่โดยสืบทอดจาก TimerTask (มักสร้างเป็น Inner Class ภายในคลาสหลัก) ในที่นี้ตั้งชื่อคลาสว่า MyTask และภายในคลาสนี้ ให้ Override เมธอด run โดยระบุการทำงานที่เราต้องการทำทุกๆช่วงเวลาหนึ่งลงไป ยกตัวอย่างเช่น ถ้าต้องการเปลี่ยนภาพใน ImageView ทุกๆ 2 วินาที ก็ให้ใส่โค้ดที่ใช้เปลี่ยนภาพลงในเมธอด run นี้- อาร์กิวเมนต์ตัวแรกคืออินสแทนซ์ (ออบเจ็ค) ของคลาส MyTask ที่เราสร้างขึ้น ซึ่งมีเมธอด run ที่เราระบุการทำงานที่ต้องการไว้
- อาร์กิวเมนต์ตัวที่สองคือ delay หรือเวลาที่ต้องการให้หน่วง (ถ่วง) ไว้ก่อนเริ่มรัน ในที่นี้ระบุค่า 0 เพราะต้องการให้รันโค้ดในเมธอด run ทันที
- อาร์กิวเมนต์ตัวที่สามคือ period หรือช่วงเวลาที่จะรันโค้ดในเมธอด run ซ้ำๆกัน หน่วยเป็นมิลลิวินาที (1/1000 ของวินาที) ในที่นี้ระบุ 1000 หมายถึงให้รันทุกๆ 1 วินาที
และใน LogCat จะมีบรรทัดหนึ่งแจ้งข้อผิดพลาดว่า
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
สาเหตุของข้อผิดพลาด เนื่องมาจากเมธอด run ที่เราเตรียมไว้ใน MyTask
นั้นจะถูกรันแยกออกมาในเธรด (Thread) ใหม่
ซึ่งเป็นลักษณะการทำงานตามปกติของ TimerTask อยู่แล้ว
แต่แอนดรอยด์มีกฎข้อหนึ่งที่สำคัญมากซึ่งมือใหม่มักไม่ค่อยรู้ นั่นก็คือ
โค้ดที่จะสามารถเข้าถึง UI ได้ ต้องเป็นโค้ดในเธรดหลัก (เธรดที่สร้าง UI
ขึ้นมา) เท่านั้น ในที่นี้เราพยายามเข้าถึง ImageView จากโค้ดในเธรดอื่น
แอนดรอยด์ก็เลยไม่อนุญาตแต่ปัญหานี้แก้ได้ไม่ยากครับ แอนดรอยด์เตรียมทางออกไว้แล้ว โดยให้เรียกเมธอด runOnUiThread ของแอคทิวิตี แล้วระบุอาร์กิวเมนต์เป็นออบเจ็ค Runnable ที่คุณทำการ Override เมธอด run ของมัน
โปรเจ็ค TestTimer
ที่อธิบายไปข้างต้นคือหลักการคร่าวๆในการใช้ Timer ร่วมกับ TimerTask ทีนี้มาดูโค้ดเต็มๆบ้างครับ โปรเจ็ค TestTimer นี้เป็นแอพที่จะแสดงภาพตัวเลข 0 ถึง 9 ออกมาตามลำดับทีละตัวเลข โดยเปลี่ยนตัวเลขทุกๆ 1 วินาที การทำงานของ Timer จะเริ่มเมื่อคลิกปุ่ม Start Timer และจะสิ้นสุดเมื่อแสดงถึงเลข 9 แล้วLayout File (ไฟล์ activity_main.xml)
แอคทิวิตี (ไฟล์ MainActivity.java)
ผลการรัน
Image Courtesy of OpenClipArt.org
ConversionConversion EmoticonEmoticon