Volley คือไลบรารีเครือข่ายสำหรับ Android ที่พัฒนาโดย Google สำหรับการดàเนินการคำขอ HTTP อย่างมีประสิทธิภาพและการโหลดภาพ ไลบรารีจัดการพูลเธรดโดยอัตโนมัติ แคชคำตอบและจัดลàดับความสำคัญของคำขอ ตามGoogle, 2025 Volley ยังคงเป็นตัวเลือกยอดนิยมสำหรับโปรเจกต์ที่ต้องการเริ่มต้นอย่างรวดเร็วโดยไม่ต้องกำหนดค่าพึ่งพาที่ซับซ้อน
ประเด็นสำคัญ
Volley คือไลบรารีสำหรับการสื่อสารเครือข่ายในแอปพลิเคชัน Android ที่ Google นำเสนอในงานประชุม I/O 2013 ชื่อ Volley หมายถึง «การยิงพร้อมกัน» — ไลบรารีถูกออกแบบมาเพื่อดำเนินการคำขอที่รวดเร็วหลายรายการพร้อมกัน ซึ่งเป็นลักษณะเฉพาะของแอปพลิเคชันที่เน้น UI ซึ่งความเร็วในการตอบสนองของอินเทอร์เฟซมีความสำคัญ
Volley ถูกสร้างขึ้นเพื่อแก้ปัญหาของ HttpURLConnection และ AsyncTask: การจัดการเธรดด้วยตนเอง การขาดแคช ความซับซ้อนของการจัดลำดับความสำคัญของคำขอ และโค้ดที่ยุ่งยาก Google วางตำแหน่ง Volley เป็นไลบรารีสำหรับการดำเนินการแบบ «fire-and-forget» — คำขอขนาดเล็กที่แสดงผลทันทีในอินเทอร์เฟซ
สถาปัตยกรรมของ Volley ประกอบด้วยสามองค์ประกอบหลัก: RequestQueue (ตัวจัดการคิว), CacheDispatcher (เธรดสำหรับคำตอบที่ถูกแคช) และ NetworkDispatcher (เธรดเครือข่าย) สถาปัตยกรรมนี้กระจายคำขอโดยอัตโนมัติ: ตรวจสอบแคชก่อน และเฉพาะเมื่อไม่มีแคชจึงดำเนินการคำขอเครือข่าย ซึ่งช่วยลดความล่าช้าสำหรับข้อมูลที่ซ้ำได้ 50–80%
RequestQueue คือคลาสหลักของ Volley วัตถุ Request<T> จะถูกเพิ่มเข้าไป และคิวจะกระจายไปยังเธรดสองประเภทโดยอัตโนมัติ: CacheDispatcher (หนึ่งเธรด จัดการคำขอที่อาจมีแคช) และ NetworkDispatcher (หลายเธรด ดำเนินการคำขอ HTTP จริง) โดยค่าเริ่มต้น Volley สร้าง 4 เธรดเครือข่าย
เมื่อเพิ่มคำขอ RequestQueue จะตรวจสอบว่าสามารถให้บริการจากแคชได้หรือไม่ หากแคชมีคำตอบที่ทันสมัย CacheDispatcher จะส่งคืนทันทีโดยไม่ต้องมีคำขอเครือข่าย หากแคชล้าสมัยหรือไม่มี คำขอจะถูกส่งต่อไปยัง NetworkDispatcher ลำดับความสำคัญของคำขอ (low, normal, high, immediate) กำหนดลำดับการประมวลผลภายในคิว — คำขอที่มีลำดับความสำคัญสูงจะถูกประมวลผลก่อนคำขอปกติ
หลังดำเนินการคำขอ ผลลัพธ์จะถูกส่งไปยังเธรดหลัก (UI thread) ผ่าน Handler Volley จะสลับ callback onResponse() และ onErrorResponse() ไปยังเธรดหลักโดยอัตโนมัติ ดังนั้นสามารถอัปเดตอินเทอร์เฟซได้โดยตรงใน callback โดยไม่ต้องสลับเธรดเพิ่มเติม ซึ่งช่วยให้โค้ดง่ายขึ้นและกำจัดข้อผิดพลาดเกี่ยวกับเธรดทั้งหมด
คุณสมบัติอีกอย่างของ Volley คือ การตัดรายการคำขอซ้ำโดยอัตโนมัติ หากคำขอ GET ที่เหมือนกันสองรายการไปยัง URL เดียวกันด้วยพารามิเตอร์เดียวกันถูกเพิ่มในคิว Volley จะดำเนินการเพียงรายการเดียวและส่งคืนคำตอบเดียวกันให้ทั้งสอง callback ซึ่งมีประโยชน์โดยเฉพาะสำหรับหน้าจอที่หลายคอมโพเนนต์ขอข้อมูลเดียวกันอย่างอิสระ — ตัวอย่างเช่น โปรไฟล์ผู้ใช้ที่จำเป็นทั้งส่วนหัวและส่วนการตั้งค่าพร้อมกัน
แต่ละคำขอ ผ่านขั้นตอนต่างๆ: สร้าง Request เพิ่มใน RequestQueue ตรวจสอบแคช (CacheDispatcher) ดำเนินการคำขอ HTTP (NetworkDispatcher) วิเคราะห์คำตอบผ่าน Response.Listener ส่งผลลัพธ์ไปยัง UI thread เมื่อยกเลิกคำขอ (cancel) RequestQueue จะลบออกจากคิวและป้องกันการเรียก callback
Volley ยังรองรับ RetryPolicy ซึ่งกำหนดจำนวนครั้งในการลองใหม่เมื่อเกิดข้อผิดพลาด DefaultRetryPolicy โดยค่าเริ่มต้นจะลองใหม่หนึ่งครั้งด้วยหมดเวลา 2.5 วินาที สำหรับการเชื่อมต่อที่ไม่เสถียร สามารถเพิ่มจำนวนครั้งลองใหม่เป็น 3 และหมดเวลาเป็น 10 วินาที RetryPolicy แบบกำหนดเองถูกนำไปใช้ผ่านอินเทอร์เฟซ RetryPolicy ด้วยเมธอด getCurrentTimeout, getCurrentRetryCount และ retry
Volley มี ประเภทคำขอสำเร็จรูป สำหรับรูปแบบข้อมูลทั่วไป แต่ละประเภทใช้คลาสนามธรรม Request<T> และกำหนดวิธีการวิเคราะห์คำตอบ สำหรับรูปแบบที่กำหนดเอง คุณสามารถสร้างประเภทของคุณเองโดยการแทนที่เมธอด parseNetworkResponse
| ประเภทคำขอ | ประเภทที่ส่งคืน | วัตถุประสงค์ |
|---|---|---|
| StringRequest | String | รับคำตอบข้อความดิบ |
| JsonObjectRequest | JSONObject | วิเคราะห์วัตถุ JSON |
| JsonArrayRequest | JSONArray | วิเคราะห์อาร์เรย์ JSON |
| ImageRequest | Bitmap | โหลดและถอดรหัสภาพ |
| ClearCacheRequest | — | ล้างแคชของ Volley |
เพื่อทำงานกับ Gson หรือ Kotlinx Serialization คุณสามารถสร้าง Request<T> แบบกำหนดเองที่ใช้ตัววิเคราะห์ที่เลือกใน parseNetworkResponse ซึ่งช่วยให้รับวัตถุที่ระบุชนิดได้โดยตรง หลีกเลี่ยงการวิเคราะห์ JSONObject ด้วยตนเอง วิธีการนี้มีประโยชน์โดยเฉพาะสำหรับโปรเจกต์ที่ใช้การซีเรียลไลซ์ผ่าน Gson หรือ Moshi อยู่แล้ว
สำหรับการส่งข้อมูล Volley รองรับสามประเภทของ body: JSONObject (ผ่าน JsonObjectRequest ด้วยเมธอด POST), Form-encoded (ผ่าน HashMap<String, String> ในตัวสร้าง) และ Multipart (ผ่าน MultipartRequest แบบกำหนดเอง) คำขอ Multipart มีประโยชน์สำหรับการอัปโหลดภาพและไฟล์ แต่ต้องดำเนินการด้วยตนเองเนื่องจาก Volley ไม่มีการรองรับ multipart/form-data ในตัว ซึ่งแตกต่างจาก OkHttp หรือ Dio
ข้อจำกัดของ Volley เริ่มเห็นได้ชัดเมื่อทำงานกับคำตอบขนาดใหญ่ Volley โหลดคำตอบทั้งหมดลงในหน่วยความจำก่อนส่งต่อไปยัง callback ซึ่งอาจทำให้เกิด OutOfMemoryError สำหรับไฟล์ JSON ที่ใหญ่กว่า 10–20 MB สำหรับการดาวน์โหลดไฟล์ขนาดใหญ่ Volley ไม่เหมาะสม — ใช้ DownloadManager หรือ OkHttp ด้วย ResponseBody แบบสตรีม Volley ยังไม่รองรับการดาวน์โหลดต่อหลังจากถูกขัดจังหวะ (Range header) และไม่ทำงานกับโปรโตคอลสตรีมเช่น Server-Sent Events หรือ WebSocket แบบเรียลไทม์
มาดู ตัวอย่างพื้นฐาน — StringRequest สำหรับรับข้อมูลจากเซิร์ฟเวอร์ ขั้นแรก สร้าง RequestQueue ผ่าน Volley.newRequestQueue(context) จากนั้นสร้างคำขอด้วย URL และ callback ความสำเร็จและข้อผิดพลาด
val queue = Volley.newRequestQueue(context)
val request = StringRequest(
Request.Method.GET,
"https://api.github.com/users/octocat",
{ response ->
println("คำตอบ: $response")
},
{ error ->
println("ข้อผิดพลาด: ${error.message}")
}
)
queue.add(request)
สำหรับ คำขอ JSON ใช้ JsonObjectRequest ซึ่งจะวิเคราะห์คำตอบเป็น JSONObject โดยอัตโนมัติ Volley รองรับคำขอ GET และ POST สำหรับ POST จะส่ง JSONObject ใน body ของคำขอ
val jsonBody = JSONObject()
jsonBody.put("name", "New Repo")
jsonBody.put("description", "Created via Volley")
val request = JsonObjectRequest(
Request.Method.POST,
"https://api.github.com/user/repos",
jsonBody,
{ response ->
println("สร้างแล้ว: ${response.getString("id")}")
},
{ println("ข้อผิดพลาด: $it") }
)
queue.add(request)
ในการยกเลิกคำขอ ใช้ เมธอด cancel() หรือการยกเลิกเป็นกลุ่มตามแท็ก เมื่อยกเลิก Volley จะไม่เรียกทั้ง onResponse และ onErrorResponse ซึ่งป้องกันการอัปเดตอินเทอร์เฟซหลังจากออกจากหน้าจอ ซึ่งสำคัญสำหรับการป้องกันหน่วยความจำรั่วใน Activity และ Fragment
request.tag = "profile_request"
queue.add(request)
// การยกเลิกเมื่อออกจากหน้าจอ
queue.cancelAll("profile_request")
ImageLoader คือคลาสหุ้มรอบ RequestQueue ที่ปรับให้เหมาะสำหรับการโหลดภาพ รองรับแคชหน่วยความจำ (LruCache) และยกเลิกคำขอโดยอัตโนมัติเมื่อ ImageView ถูกใช้ซ้ำในรายการ RecyclerView ImageLoader ยังปรับขนาดภาพให้พอดีกับขนาด View เพื่อประหยัดหน่วยความจำ
NetworkImageView คือ View แบบกำหนดเองที่ทำงานร่วมกับ ImageLoader และจัดการการโหลดโดยอัตโนมัติ: แสดงตัวยึดตำแหน่งระหว่างโหลด แทนที่ด้วยข้อผิดพลาดเมื่อล้มเหลว และยกเลิกคำขอเมื่อ View ออกจากหน้าจอ DefaultImageUrlLoader โหลดภาพตาม URL และเก็บใน LruCache เพื่อการแสดงซ้ำอย่างรวดเร็ว
ในการใช้ ImageLoader เพียงสร้างอินสแตนซ์ผ่าน ImageLoader(queue, ImageCache) โดย ImageCache คือการใช้งานอินเทอร์เฟซ ImageCache ด้วย LruCache ภายใน NetworkImageView ในเลย์เอาต์ XML เชื่อมต่อกับ ImageLoader ผ่านเมธอด setImageUrl() และการโหลดทั้งหมดเกิดขึ้นโดยอัตโนมัติโดยไม่ต้องมีโค้ดเพิ่มเติมสำหรับจัดการตัวยึดตำแหน่งและข้อผิดพลาด
การสร้าง RequestQueue ในทุก Activity เป็นข้อผิดพลาดทั่วไปที่นำไปสู่การทำซ้ำของเธรดและความสับสนในแคช แนะนำให้สร้าง RequestQueue ครั้งเดียวใน Application หรือผ่านคลาส singleton มิฉะนั้น แต่ละหน้าจอจะมีพูลเธรดของตัวเองและแคชจะถูกเก็บแยกต่างหากสำหรับแต่ละคิว
การละเลยการยกเลิกคำขอ เมื่อหมุนหน้าจอ เมื่อการกำหนดค่าเปลี่ยนแปลง Activity จะถูกสร้างใหม่และ callback ของ Activity เก่ายังคงอยู่ในหน่วยความจำ ซึ่งนำไปสู่การรั่วไหลและความพยายามในการอัปเดต View ที่ถูกทำลาย ยกเลิกคำขอใน onStop() ผ่าน cancelAll() ด้วยแท็กเฉพาะของ Activity เสมอ
Volley ไม่รองรับ HTTP/2 และ coroutine — นี่ไม่ใช่ข้อผิดพลาดในการใช้งาน แต่เป็นข้อจำกัดทางสถาปัตยกรรม Volley ถูกสร้างขึ้นในปี 2013 และไม่รองรับโปรโตคอลสมัยใหม่และ Kotlin coroutine สำหรับโปรเจกต์ใหม่ Google แนะนำให้ใช้ Retrofit + OkHttp Volley เหมาะสำหรับการสนับสนุนโปรเจกต์เดิมหรือแอปพลิเคชันง่ายๆ ที่มีความต้องการเครือข่ายน้อยที่สุด
คำถามที่พบบ่อย
Volley ล้าสมัยสำหรับโปรเจกต์ใหม่ — Google ไม่ได้อัปเดตไลบรารีตั้งแต่ปี 2017 สำหรับแอปพลิเคชันสมัยใหม่ ใช้ Retrofit + OkHttp หรือ Ktor Client Volley สามารถใช้ได้เฉพาะสำหรับการสนับสนุนโค้ดเดิมที่มีอยู่หรือในโปรเจกต์การศึกษาง่ายๆ ที่มีงานเครือข่ายน้อยที่สุด
ขาดการรองรับ เทคโนโลยีสมัยใหม่: HTTP/2, Kotlin coroutine, การพัฒนาข้ามแพลตฟอร์ม และการซีเรียลไลซ์แบบมีชนิด Volley ใช้ JSONObject และ JSONArray โดยไม่มีชนิด ซึ่งนำไปสู่ข้อผิดพลาด runtime เมื่อโครงสร้าง JSON ไม่ตรงกับที่คาดหวัง
ผ่าน ImageLoader และ NetworkImageView ImageLoader ใช้ LruCache สำหรับแคชภาพในหน่วยความจำและยกเลิกคำขอโดยอัตโนมัติเมื่อนำ View กลับมาใช้ใหม่ NetworkImageView แสดงตัวยึดตำแหน่งระหว่างโหลดและแทนที่ด้วยภาพที่โหลดแล้วหรือตัวบ่งชี้ข้อผิดพลาด
ในทางเทคนิคได้ — ผ่าน wrapper suspendCoroutine { } รอบ callback ของ Volley แต่ไม่มีข้อดีเนื่องจาก Volley ไม่รองรับการยกเลิกตามการยกเลิก coroutine และไม่ทำงานโดยตรงกับ Dispatchers.IO ควรใช้ Ktor Client ที่มีการรองรับ coroutine แบบเนทีฟจะดีกว่า
Timeout ถูกกำหนดผ่าน RetryPolicy โดยค่าเริ่มต้น DefaultRetryPolicy ใช้ timeout 2.5 วินาทีและลองใหม่หนึ่งครั้ง เปลี่ยนพารามิเตอร์: request.retryPolicy = DefaultRetryPolicy(10000, 1, 1.0f) — 10 วินาที timeout หนึ่งครั้งลอง
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม