[Dev] แนะนำการใช้งาน OkHttp Library สำหรับ Android

สำหรับ App บน Android นั้น ส่วนใหญ่ มักจะมีส่วนของการเชื่อมต่อกับฝั่ง Server เพื่อรับ-ส่งข้อมูลกัน ซึ่งการเชื่อมต่อกับฝั่ง Server นั้น เรามักจะใช้ Class ที่ Implement Interface HttpClient ซึ่งอยู่ใน Package org.apache.http.client นั่นเอง

Android-Developer-logo_OkHttp-Library

ถ้าใครที่เคยเขียนมาบ้าง จะรู้ว่า การใช้งานมันยุ่งยากมาก ทั้งในด้านของการเขียนคำสั่ง การจัดการกับ Error และ Exception ต่าง ๆ รวมถึงการเขียนคำสั่งไม่ให้อยู่บน Main Thread ตามกฎที่ถูกกำหนดไว้ เพื่อป้องกันการเกิด ANR (Application Not Responding) จากการเชื่อมต่อที่ใช้เวลานาน

และที่สำคัญ Interface HttpClient นั้น ทาง Google ได้ประกาศให้เลิกใช้แล้ว ใน API level 22 (Android 5.1) ดังรูปด้านล่าง

Interface HttpClient บน API level 22
Interface HttpClient บน API level 22

และแนะนำให้ใช้งาน openConnection() จาก Class URL ที่ Package java.net แทน

ก็แค่ Deprecated เอง มันก็ยังใช้ได้อยู่ไม่ใช่เหรอ

ประโยคข้างบน คงมีหลาย ๆ คนคิดแบบนี้ แต่ความเป็นจริงแล้ว เมื่อทาง Google ประกาศเลิกใช้แล้ว นั่นหมายความว่า ในอีกไม่กี่เวอร์ชั่นต่อจากนี้ไป มันจะถูกถอดออกไป…

และการมาของ Android M ที่เพิ่งเปิดตัวไปในงาน Google I/O 2015 ที่เพิ่งจบไปไม่กี่วันมานี้ แน่นอนว่าจะต้องมี API Level ใหม่ออกมา (ณ ตอนนี้เป็น Developer Preview กำหนด API Level เป็น 22+ หรือ mnc-preview-1) ซึ่งใน Developer Documentation ก็พบว่า Package org.apache.http.client นั้น ได้ถูกถอดออกไปแล้ว

Android API Differences Report
Android API Differences Report

การที่ Package org.apache.http.client ถูกถอดออกนั้น เป็นผลให้ Interface HttpClient ไม่สามารถใช้งานได้อีกต่อไป

สำหรับใครที่คิดว่า ตัวเองไม่ได้ใช้ HttpClient แต่ใช้ Library นั่น อย่าเพิ่งดีใจไปครับ ลองตรวจสอบดูก่อนนะ เพราะเท่าที่รู้มา หลาย ๆ Library ใช้ HttpClient ทำงานอยู่เบื้องหลัง แปลว่าจะไม่สามารถใช้งานได้แล้ว…

สำหรับบทความนี้ ผมจึงขอแนะนำ OkHttp Library ที่พัฒนาโดย Square, Inc. ใช่แล้วครับ Square ที่ทำเกมส์ซีรีส์ชื่อดังอย่าง Final Fantasy นั่นแหล่ะ โดยจุดเด่นของ Library นี้อยู่ที่ ใช้ Class HttpURLConnection ที่ Package java.net นั่นเอง

อันที่จริง จุดเด่นอื่น ๆ มีอีกเยอะแยะมากมาย เช่นการใช้งานได้กับหลากหลาย Protocol แต่ว่า นาทีนี้ คงหนีไม่พ้นเรื่อง Deprecated นี่ล่ะ

โดยผมจะแนะนำถึงการใช้งานเบื้องต้นเท่านั้น ซึ่งก็น่าจะเพียงพอต่อการใช้งานแล้วล่ะ

 

List of contents

 

How to use OkHttp

ก่อนอื่น ต้องทำการเพิ่ม Library ให้กับ Project ของเราซะก่อน สำหรับ Android Studio นั้น สามารถเพิ่ม Dependency ใน build.gradle ของ Module app เรา ดังนี้

แล้วทำการ Sync ให้เรียบร้อย ซึ่ง OkHttp จะมีการใช้งาน Okio Library อยู่เบื้องหลัง ซึ่งมันจะถูก Sync มาด้วยแล้ว ไม่จำเป็นต้องเพิ่ม Dependency ของ Okio ลงไปด้วย

ถ้าไม่ได้ใช้ Android Studio ก็สามารถหา .jar มาใช้ได้จากเว็บ OkHttp

ตรวจสอบ Version ล่าสุดของ OkHttp Library ได้ที่ http://square.github.io/okhttp/

 

ก่อนจะเริ่มทดลองใช้งานกัน ต้องทำความเข้าใจกันก่อนว่า OkHttp Library นั้น ไม่ได้ทำงานบน Thread ใหม่ กรณีใช้งานแบบ Synchronous และจะทำงานบน Thread ใหม่ให้ในกรณีการใช้งานแบบ Asynchronous แต่ว่าไม่ได้ส่งผลการทำงานกลับมายัง Main Thread ให้ด้วย เพราะฉะนั้น เป็นหน้าที่ของเราที่ยังจะต้อง Handle เรื่องเหล่านี้เอง ว่าแล้วไปลองกันเลยดีกว่า

 

Synchronous Get

การใช้งานแบบ Synchronous นั้น อย่างที่เกริ่นไปแล้วว่า ไม่ได้ทำงานบน Thread ใหม่ให้ ดังนั้นเราจำเป็นต้องสร้าง Thread ใหม่เพื่อทำงาน และส่งผลการทำงานกลับไปยัง Main Thread เอง ในตัวอย่างต่อไปนี้จะใช้ AsyncTask ในการทำงาน โดยผมจะทำการ Implement จาก Anonymous Class และใช้งานเลย ดังนี้

ในบรรทัดที่ 1 ทำการสร้าง Instance จาก Anonymous Class โดยจะ Implement 2 Method คือ doInBackground() และ onPostExecute() และทำการเรียกใช้ Method execute() เพื่อทำงานเลย ในบรรทัดที่ 13

ทีนี้เราก็ใช้งาน OkHttp ในการเชื่อมไปยัง Server ได้แล้ว โดยการเขียนคำสั่งใน Method doInBackground() ดังนี้

ก่อนอื่นต้องสร้าง Instance จาก Class OkHttpClient ขึ้นมาก่อน และใช้ Class Request.Builder ช่วยสร้าง Request ให้ (ในตัวอย่างนี้ จะเชื่อมต่อไปที่ http://date.jsontest.com/ ลองเปลี่ยนไปเป็น URL อื่นก็ได้นะ) แล้วจึงนำไปเชื่อมต่อกับ Server โดยนำ OkHttpClient เรียกใช้งาน Method newCall() จะได้ Return มาเป็นชนิด Call แล้วเรียกใช้งาน Method execute() อีกทีหนึ่ง

ตรง Method execute() นี่ล่ะ ที่จะทำงานเป็นแบบ Synchronous

Method execute() จะ Return มาเป็นชนิด Response เมื่อการรับ-ส่งข้อมูลกับ Server เสร็จสิ้น โดยสามารถตรวจสอบผลการทำงานได้จาก Method isSuccessful() และหากทำงานสำเร็จ สามารถอ่านข้อมูลได้จาก Method body() ของ Response ซึ่งจะ Return มาเป็น ResponseBody ซึ่งจะมี Method string() ในการอ่านข้อมูลออกมา ดังในตัวอย่างบรรทัดที่ 9 ด้านบน

เมื่อเรา Return ผลการทำงานออกไปจาก Method doInBackground() ของ AsyncTask แล้ว ก็ถึงเวลาที่จะนำผลการทำงานไปใช้ โดยเขียน Code ไว้ใน Method onPostExecute() ซึ่ง Method นี้ จะทำงานบน Main Thread แล้วล่ะ ดังนี้

ก็ไม่ได้มีอะไรซับซ้อนเลย เพราะ AsyncTask ในตัวอย่างนี้ เราเป็นคนกำหนดให้ Return เป็นชนิด String อยู่แล้ว นำไปใช้งานกับ View ได้เลย

เมื่อรวม ๆ Code แล้ว ก็จะได้เป็น…

อีกนิด…

ถ้าใครที่เขียนเว็บมานานพอสมควร จะทราบว่า ยังมีส่วนหัวของข้อมูลอีกส่วนนึง ที่เรียกว่า Header ซึ่งจะอยู่ก่อนส่วนของข้อมูลที่เราอ่านมาได้แล้วจากตัวอย่างข้างบน โดยสามารถอ่านข้อมูลออกมาได้จาก Response ดังนี้

 

และเนื่องจากจะต้องใช้งานผ่าน Internet ก็อย่าลืมเพิ่ม Use Permission ในไฟล์ AndroidManifest.xml ด้วย ดังนี้

 

Asynchronous Get

มาดูวิธีใช้งานแบบ Asynchronous กันบ้าง ใน Library ได้เตรียม Method enqueue() ของ Class Call ไว้ให้ใช้งาน โดยจะทำงานในลักษณะ Asynchronous โดยจะแยกการทำงานไปอยู่บน Thread ใหม่ให้ ส่งผลการทำงานกลับมาในลักษณะของ Listener ซึ่งเราจะต้อง Implement Interface Callback เพื่อรอรับผลการทำงาน เพียงแต่ว่า ผลการทำงานที่ส่งกลับมาให้ จะไม่ได้อยู่บน Main Thread ซึ่งตรงนี้ เราจะต้องจัดการเอาเอง แต่ก็ไม่ได้ยุ่งยากอะไร มาดู Code กันเลยดีกว่า…

เริ่มด้วยการสร้าง OkHttpClient และ Request แบบเดียวกับ Synchronous เลย (ไม่ต้องอธิบายซ้ำเน๊อะ) แล้วนำ OkHttpClient มาเรียกใช้งาน Method newCall() จะได้ Return มาเป็นชนิด Call แล้วเรียกใช้งาน Method enqueue() อีกทีหนึ่ง

ตรง Method enqueue() นี่ล่ะ ที่จะทำงานเป็นแบบ Asynchronous

Method enqueue() นั้น ต้องการ Parameter 1 ตัว เป็นชนิด Interface Callback ซึ่งในตัวอย่างด้านล่างนี้ จะ Implement ลงไปแบบ Inline เลย ซึ่ง Interface Callback จะให้เรา Implement 2 Methods คือ onFailure() และ onResponse() คงเดาออกกันเน๊อะว่า Method ไหน จะเกิด Callback กลับมาเมื่อไหร่…

 

ทั้ง onFailure() และ onResponse() จะยังไม่ได้กลับมาทำงานอยู่บน Main Thread

ถ้าอย่างนั้น ผมขอเพิ่มในส่วนของการกลับไปยัง Main Thread ไว้ด้วยเลย โดยการเพิ่ม Method updateView() ดังนี้

และในบรรทัดที่ 8 นั้น ผมจะลบ throws IOException ออกไป เนื่องจากผมต้องการจัดการกับ Exception เองภายใน Method onResponse()

กลับมาที่ Method onFailure() จะถูก Callback มาเมื่อเกิดความผิดพลาดเกิดขึ้น โดยเราสามารถตรวจสอบ Request ที่เกิดความผิดพลาดได้จาก Parameter ตัวแรก และ IOException ที่เกิดขึ้นจาก Parameter ตัวที่สอง

Code ด้านล่างนี้ จะนำ Exception Message ส่งไปให้ Method updateView() ดังนี้

 

ส่วน Method onResponse() จะถูก Callback เมื่อการรับ-ส่งข้อมูลกับ Server เสร็จสิ้น โดยจะมี Response ส่งกลับมาให้ด้วยใน Parameter ซึ่งก็จะเหมือนกับแบบ Synchronous แล้วล่ะ

รวม ๆ Code ก็จะได้เป็น…

อย่าลืม Use Permission เน้ออออ

 

Accessing Headers

สำหรับกรณีที่ต้องการ Custom Header สำหรับการ Request นั้น จะมี Method ใน Class Request.Builder ให้เราใส่ข้อมูลลงไปได้ ตัวอย่างเช่น

ใน Code ด้านบน จะใช้ Method header() ในการกำหนดข้อมูล Header และจะใช้ Method addHeader() ในการเพิ่มข้อมูลลงไปอีกนั่นเอง

เห็น API หลาย ๆ ตัว ชอบให้ส่งข้อมูลไปกับ Header เพราะฉะนั้น OkHttp Library ก็ตอบโจทย์ตรงนี้ด้วยนะ

หลังจากนั้น จะ Call แบบ Synchronous หรือ Asynchronous ก็เลือกตามใจชอบเลย…

 

Posting a String

มาดูการโพสข้อมูลไปยัง Server กันบ้าง เราสามารถใช้ Method post() ของ Class Request.Builder ในการโพสข้อมูลได้ ซึ่งมันต้องการ Parameter เป็นชนิด Class RequestBody แต่ใน Class RequestBody นั้น มี Static Method ชื่อว่า create() ที่จะ Return เป็น RequestBody มาให้ ตัวอย่างด้านล่างนี้ จะเป็นการโพส String ไปยัง Server นั่นเอง

สำหรับ Method create() ของ Class RequestBody นั้น ยังมีอีกหลาย Overload ให้เลือกใช้ สามารถ Post ข้อมูลชนิดอื่น ๆ ได้อีกด้วย

 

เป็นไงกันบ้างครับ OkHttp Library น่าใช้งานไม๊ครับ

สำหรับบทความแนะนำ OkHttp Library ก็ขอจบแค่นี้ละกันนะ แค่นี้ก็คงเพียงพอต่อการนำไปประยุกต์ใช้กันแล้วล่ะ ถ้าอยากลงลึกไปมากกว่านี้ แนะนำให้อ่าน wiki ของ OkHttp Library บน GitHub ดูครับ ละเอียดยิบเลยทีเดียว

หรือจะศึกษารายละเอียด Code ทั้งหมด ที่ผมนำมาเขียนบทความนี้ ก็ดูได้ที่ Project บน GitHub ของผมได้เลย

Leave a Reply

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.