วิธีใช้งาน AsyncTask บน Android
เชื่อว่าหลายๆคนที่เขียน Android Application ต้องมีความคุ้นเคยกับ AsyncTask
กันแน่นอน โดยเฉพาะเมื่อต้องการเชื่อมต่อ Internet ผ่าน HTTP ต่างๆ ล้วนต้องใช้ AsyncTask มาช่วยทั้งสิ้น หรือเวลาต้องการประมวลผลอะไรไว้ที่ background thread เพื่อไม่ให้กระทบกับตัว Main UI วันนี้ก็เลยทำเป็นบทความ อธิบาย AsyncTask วิธีการใช้งาน AsyncTask หลีกเลี่ยงการเกิด Exception เมื่อติดต่อผ่าน HTTP โดยใช้ AsyncTask แทน โดยบทความนี้จะโฟกัสไปที่การเชื่อมต่อ Internet โดยใช้ AsyncTask เพื่อหลีกเลี่ยง OnMainThreadException
ครับ
AsyncTask คืออะไร?
AsyncTask
นั้นเป็น abstract class ที่ทาง Android นั้นจัดเตรียมมาให้เราเพื่อทำการประมวลผล หรือทำงานเป็น background โดยไม่ต้องไปยุ่งกับตัว UI หลัก อย่างเช่น กรณีต้องการดึง content จากเว็บไซต์เว็บหนึ่ง เพื่อมาแสดงบนแอพพลิเคชันของเรา เราก็จะใช้ AsyncTask
ช่วยในการคำนวณ ประมวลผล โดยเมื่อ AsyncTask ทำงานอยู่ มันจะไม่กระทบกับหน้าจอ UI ของเรา
การใช้งาน AsyncTask
สำหรับคลาส AsyncTask
ดู Reference ได้ที่นี่ จะมีการใช้งานดังนี้ (ตัวอย่าง ผมไม่ได้ทำการ override เมธอดมาทั้งหมดนะครับ)
เวลาเรียกใช้การก็แค่
จากโครงสร้าง AsyncTask ด้านบน เรามาดู arguments ของแต่ละตำแหน่งว่ามันคืออะไรกันดีกว่า จาก
- String : ตัวแรกนั้นคือ parameter ที่ส่งไปครับ สมมติตัวอย่างนี้จะใช้ดึง content จากเว็บ params นี้ก็จะเป็น URI ของเว็บไซต์
- Integer: ตัวนี้คือ ค่า Progress ไว้สำหรับแสดง ค่า Progressbar หรือทำพวก Loading ต่างๆ
- String: ตัวที่สาม คือ ค่าผลลัพท์ ที่ต้องการ return กลับไป
เมื่อรู้จักทั้ง 3 parameters แล้ว ต่อไปก็มารู้จัก เมธอดของมัน ว่าจะเรียกใช้ตอนไหน บ้าง
เมธอดนี้ จะเป็นเมธอดที่ คอยทำงานเป็น Background ให้เรา เช่น เชื่อมต่อ HTTP ไปยังเว็บไซต์ โดยรับ ที่อยู่ URI เว็บจากค่า String ตัวแรกของ AsyncTask
มา จากนั้นก็ทำการประมวลผล
เมธอดนี้จะเอาไว้แสดงค่า ProgressBar ว่าทำงานไปเท่าไหร่แล้ว โดยมากก็จะเป็นการนับ 0 ถึง 100 โดยค่า 0 - 100 มันก็ได้มาจาก Integer ซึ่งเป็น parameter ตัวที่สองของ AsyncTask
แต่ในบทความนี้ ผมไม่พูดถึงครับ เพราะว่าโหลดเนื้อหาจากเว็บไซต์ คิดว่าไม่จำเป็นต้องใช้ ส่วนมากเอาไว้ใช้เวลาโหลดรูปภาพขนาดใหญ่ จะเห็นผลดีกว่า
เมธอดนี้จะถูกเรียกเมื่อการทำงานที่ Background นั้นจบลงแล้ว โดยรับ parameter เป็น String ที่ได้ผลลัพธ์มาจากเมธอด doInBackground
ส่วนมากเมธอดนี้จะเอาไว้อัพเดท set ค่าต่างๆ ครับ เช่น setText ให้กับ EditText หรือ set ค่าให้กับ WebView เป็นต้น
เอาละ เมื่อรู้ถึงการใช้งาน เบื้องต้นของ AsyncTask
ไปแล้ว คราวนี้มา Learning by Doing กันครับ เรียนรู้จากการลงมือทำ เรียนรู้จากตัวอย่างครับ
สร้างโปรเจ็ค
ทำการสร้างโปรเจ็ค จะด้วย Android Studio หรือ Eclipse ก็แล้วแต่ หากสร้างไม่เป็น อ่านได้จากบทความข้างล่างนี้ หากทำเป็นแล้ว ข้ามไปเลย
เมื่อสร้างโปรเจ็คได้แล้ว จะโฟกัสแค่ 2 ไฟล์ คือ MainActivity.java
สำหรับเขียนโค๊ด และ activity_main.xml
สำหรับหน้า Layout
สำหรับหน้าเลเอาท์ จะมีแค่ EditText ให้ใส่ URI ของเว็บไซต์ จากนั้นก็มีปุ่ม Button ไว้สำหรับ Submit ค่า สุดท้ายก็เป็น WebView เอาไว้แสดงเนื้อหาของเว็บไซต์ หน้าตาออกแบบคร่าวๆ ก็เป็นดังนี้
ตัวไฟล์ activity_main.xml
ได้ดังนี้
มาดูที่ MainActivity.java
เริ่มแรก ทำการเชื่อม View ในคลาสกับใน Layout ซะด้วย findViewById()
จริงๆ จะ extends ActionBarActivity, FragmentActivity หรือ Activity ก็ได้เหมือนกัน คลาสพวกนี้ทาง Android นั้นทำมาเพื่อ support API ต่ำๆครับ สำหรับรายละเอียด ความแตกต่าง บทความนี้ไม่ขอพูดถึงครับ
ต่อมา ทำการสร้าง inner class ชื่อว่า SimpleTask
ครับ และทำการ extends AsyncTask
ตามรูปแบบของมันเลย
จากด้านบน ผมให้ AsyncTask
มันรับ parameter เป็น URI ของเว็บไซต์ ส่วนใน doInBackground
จะเป็นการดึง content จากเว็บไซต์ โดยใช้ DefaultHttpClient
ทำการ execute
๊URI ที่ใส่ไป จากนั้นเมื่อได้ผลลัพธืแล้ว ก็ส่งค่าผลลัพธ์ไปยังเมธอด onPostExecute
ส่วนในโค๊ดด้านบน ผมยกตัวอย่าง ส่วนมากเค้าจะนิยม ให้ ProgressBar มันแสดงในเมธอด onPreExecute()
แล้วก็ dismiss มันในเมธอด onPostExecute()
แต่บทความนี้ ขี้เกียจเพิ่มครับ พอดีจัด Layout แบบ Linear ไปแล้ว ขี้เกียจแก้ :D
ส่วนขั้นตอนการ get content ใน เมธอด doInBackground()
มีดังนี้
เริ่มแรก สร้าง new instance ของ HttpGet
โดยรับเอา URI ที่ได้จาก EditText จากนั้นใช้ HttpClient.execute()
เพื่อทำการส่ง request ไปที่เว็บไซต์ จากนั้นเว็บไซต์จะส่ง response กลับมา เราก็ใช้ HttpResponse
ในการรับค่าที่ส่งกลับมา โดยผมใช้ statusCode
เพื่อเช็คว่าส่ง response กลับมาเป็น 200 หรือไม่ ตัวเลขนี้คือ HTTP Response Code หากใช่แสดงว่า ปกติ ก็ให้ทำการอ่านค่าจาก response.getEntity().getContent()
ด้วย BufferedReader
ตามตัวอย่างเลยครับ หากไม่เข้าใจ ไปอ่านพื้นฐาน File IO ของ Java ได้ครับ
ส่วนเมธอด onPostExecute
ผมให้มันไปเรียก private เมธอด ที่ชื่อ updateWebView()
โดยประกาศไว้ดังนี้
สุดท้าย ก็ setLisneter ให้กับ Button ครับ
โดยเมื่อคลิกที่ปุ่ม ก็ทำการ new SimpleTask
ขึ้นใหม่และทำการ execute
โดยรับค่าจาก EditText ที่เรากรอก ส่งไปทำงานเป็น Background ใน SimpleTask กระบวนการทำงานทั้งหมดก็มีเท่านี้แล :)
อ้อสุดท้ายจริงๆ อย่าลืม เพิ่ม permission Internet ในไฟล์ AndroidManifest.xml
ด้วยครับ
ใช้ Android-Async-HTTP แทน
ตัวอย่างนี้ต่อกันเลยนะครับ เพียงแค่เปลี่ยนวิธีการ มาใช้ Library กันบ้าง ตัวอย่างนี้คือใช้ Library ที่ชื่อว่า android-async-http สำหรับ Library ตัวนี้มีประโยชน์มากๆครับ เวลาเราใช้งานพวก HTTP ต่างๆ Features หลักๆของมัน ก็อ่านได้จากเว็บไซต์เลยครับ หลักๆทั่วไปก็พวก
- asynchronous HTTP request สามารถ handle callback ได้
- มี GET/POST ให้ใช้
- Parsing JSON ก็ทำได้ง่ายๆ
- สามารถดาวน์โหลด Binary File พวกรูปภาพ
การใช้งาน
การใช้งาน android-async-http นั้นง่ายมากๆครับ Add Library ซะก่อน วิธี Add Library ใน Eclipse ไม่ขอพูดถึงนะครับ หาอ่านได้ทั่วไป หรือไม่รู้ ก็ google ครับ
สำหรับ Android Studio เปิด build.gradle
แล้วเพิ่มนี้ลงไป ในแท็ก dependencies
Trick สำหรับการเพิ่ม Library ใน Gradle จริงๆ ถ้าเป็น Library ของ Maven ก็สามารถเพิ่มได้หมดนะครับเพราะมันจะไปดาวน์โหลดไฟล์จาก Maven อีกที คือ `compile ‘GroupId:ArtifactId:version’
จากนั้น เวลาใช้งานก็เพียงแค่
ทำการสร้าง instance ของ AsyncHttpClient ขึ้นมา จากนั้นก็เรียกเมธอด get()
โดยมี parameter เป็น URI เว็บ และ callback สำหรับส่งผลลัพธ์ด้วย onSuccess()
นำไปประยุกต์ใช้แทน AsyncTask เมื่อกี้แบบง่ายๆก็คือ ตรง onClickListener ของ Button ก็ให้เปลี่ยนมาใช้ AsyncHttpClient
แทน AsyncTask
เดิม
จากเดิม เมื่อคลิกปุ่ม Button OK โค๊ดเป็นดังนี้
ก็เปลี่ยนใหม่เป็น
ทดสอบ ลองกรอก ๊URI แล้วก็กดปุ่ม OK แล้วลองเล่นดูครับ ผลลัพธ์ที่ได้ เหมือนกันเลย จากบทความนี้ก็ได้รู้ว่าเราสามารถเชื่อมต่อ HTTP โดยการใช้ AsyncTask มาช่วยแล้ว เรายังมี Library ที่ชื่อว่า android-async-http ได้อีกด้วย แถมรู้สึกจะดีกว่าตัว AsyncTask ของ Android เองอีก สำหรับ Library สำหรับการ connect HTTP จริงๆ ก็ยังมีอีกหลายตัวครับ ที่ผมเคยใช้ก็เป็น ion ตัวนี้สามารถใช้กับการโหลด ImageView ได้อีกด้วย (เหมือนๆพวก Volley, Picasso, Universal Image Loader) แต่ตัวนี้พิเศษกว่า คือช่วยในการเชื่อมต่อ Networking แถมมี GSON ด้วย หากได้ลองใช้ รับรองติดใจครับ ^^
โค๊ดทั้งหมด
โค๊ดทั้งหมดต่อจากนี้ ผมรวมไปเขียนไว้ใน gist ดีกว่าครับ จะได้สะดวก หากมีการแก้ไข หรือมีการอัพเดทเพิ่มเติม แต่ปกติทุกบทความผมก็เขียนด้วย Markdown แล้วใ้ช้ git อยู่แล้ว เวลาแก้บทความ ก็รู้ว่าตรงไหนมีการแก้ไข แต่ว่าแยกโค๊ดออกไปเลย ก็ยิ่งง่ายขึ้น ประหยัดหน้าเว็บด้วย จะได้ไม่ยาวมาก :)
- Authors
-
Chai Phonbopit
เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust