Volley — este o bibliotecă de rețea pentru Android, dezvoltată de Google pentru executarea eficientă a cererilor HTTP și încărcarea imaginilor. Biblioteca gestionează automat pool-ul de fire, cache-uiește răspunsurile și prioritizează cererile. Potrivit Google, 2025, Volley rămâne o alegere populară pentru proiecte care necesită un start rapid fără configurarea dependențelor complexe.
Principalele puncte
Volley — este o bibliotecă pentru comunicare în rețea în aplicațiile Android, prezentată de Google la conferința I/O 2013. Numele Volley înseamnă „salvă” — biblioteca este concepută pentru executarea mai multor cereri rapide paralele, caracteristice aplicațiilor orientate pe UI, unde viteza de răspuns a interfeței este importantă.
Volley a fost creată ca soluție la problemele HttpURLConnection și AsyncTask: gestionarea manuală a firelor, lipsa cache-ului, dificultatea prioritizării cererilor și codul voluminos. Google a poziționat Volley ca bibliotecă pentru operații de tip fire-and-forget — cereri mici al căror rezultat este afișat imediat în interfață.
Arhitectura Volley include trei componente principale: RequestQueue (managerul de coadă), CacheDispatcher (fir pentru răspunsuri cache) și NetworkDispatcher (fire de rețea). Această arhitectură distribuie automat cererile: mai întâi se verifică cache-ul și doar în lipsa acestuia se execută cererea de rețea. Aceasta reduce întârzierea pentru datele repetitive cu 50–80%.
RequestQueue — clasa centrală a Volley. Obiectele Request<T> sunt adăugate în ea, iar coada le distribuie automat pe două tipuri de fire: CacheDispatcher (un fir, procesează cererile cu cache posibil) și NetworkDispatcher (mai multe fire, execută cereri HTTP reale). În mod implicit, Volley creează 4 fire de rețea.
La adăugarea unei cereri, RequestQueue verifică dacă poate fi servită din cache. Dacă cache-ul conține un răspuns actual, CacheDispatcher îl returnează imediat, fără cerere de rețea. Dacă cache-ul este vechi sau lipsește, cererea este transmisă către NetworkDispatcher. Prioritatea cererii (low, normal, high, immediate) determină ordinea de procesare în coadă — cererile cu prioritate high sunt procesate înaintea celor normal.
După executarea cererii, rezultatul este livrat în firul principal (UI thread) prin Handler. Volley comută automat callback-urile onResponse() și onErrorResponse() pe firul principal, astfel încât puteți actualiza direct interfața în callback fără comutări suplimentare. Acest lucru simplifică codul și elimină o întreagă clasă de erori legate de fire.
O altă caracteristică a Volley este deduplicarea automată a cererilor. Dacă în coadă sunt adăugate două cereri GET identice către același URL cu aceiași parametri, Volley execută doar una dintre ele și returnează același răspuns către ambele callback-uri. Acest lucru este util în special pentru ecranele unde mai multe componente solicită independent aceleași date — de exemplu, profilul utilizatorului, necesar simultan atât pentru antet, cât și pentru fragmentul cu setări.
Fiecare cerere trece printr-o succesiune de pași: crearea Request, adăugarea în RequestQueue, verificarea cache-ului (CacheDispatcher), executarea cererii HTTP (NetworkDispatcher), parsarea răspunsului prin Response.Listener, livrarea rezultatului în firul UI. La anularea cererii (cancel), RequestQueue o elimină din coadă și previne apelarea callback-urilor.
Volley suportă și RetryPolicy, care determină numărul de reîncercări la defecțiuni. DefaultRetryPolicy face implicit o singură reîncercare cu un timeout de 2,5 secunde. Pentru conexiuni instabile, numărul de reîncercări poate fi mărit la 3, iar timeout-ul — la 10 secunde. Un RetryPolicy personalizat se implementează prin interfața RetryPolicy cu metodele getCurrentTimeout, getCurrentRetryCount și retry.
Volley oferă tipuri gata făcute de cereri pentru formatele comune de date. Fiecare tip implementează clasa abstractă Request<T> și definește modul de parsare a răspunsului. Pentru formate personalizate puteți crea propriul tip, suprascriind metoda parseNetworkResponse.
| Tip cerere | Tip returnat | Destinație |
|---|---|---|
| StringRequest | String | Obținerea răspunsului text brut |
| JsonObjectRequest | JSONObject | Parsarea obiectului JSON |
| JsonArrayRequest | JSONArray | Parsarea array-ului JSON |
| ImageRequest | Bitmap | Încărcarea și decodarea imaginii |
| ClearCacheRequest | — | Golirea cache-ului Volley |
Pentru lucrul cu Gson sau Kotlinx Serialization puteți crea un Request<T> personalizat care în parseNetworkResponse folosește parserul ales. Acest lucru permite obținerea directă a obiectelor tipizate, ocolind parsarea manuală a JSONObject. O astfel de abordare este utilă în special pentru proiectele care utilizează deja serializarea prin Gson sau Moshi.
Pentru trimiterea datelor, Volley suportă trei tipuri de corp: JSONObject (prin JsonObjectRequest cu metoda POST), Form-encoded (prin HashMap<String, String> în constructor) și Multipart (prin MultipartRequest personalizat). Cererile Multipart sunt utile pentru încărcarea imaginilor și fișierelor, dar necesită implementare manuală, deoarece Volley nu are suport încorporat pentru multipart/form-data spre deosebire de OkHttp sau Dio.
Limitările Volley devin vizibile la lucrul cu răspunsuri mari. Volley încarcă întregul răspuns în memorie înainte de a-l transmite callback-ului, ceea ce poate provoca OutOfMemoryError pentru fișiere JSON mai mari de 10–20 MB. Pentru încărcarea fișierelor mari, Volley nu este potrivit — utilizați DownloadManager sau OkHttp cu ResponseBody în flux. Volley nu suportă nici reluarea descărcărilor întrerupte (Range header) și nu funcționează cu protocoale de flux precum Server-Sent Events sau WebSocket în timp real.
Să examinăm exemplul de bază — StringRequest pentru obținerea datelor de pe server. Mai întâi se creează RequestQueue prin Volley.newRequestQueue(context). Apoi se formulează cererea cu URL și callback-uri pentru succes și eroare.
val queue = Volley.newRequestQueue(context)
val request = StringRequest(
Request.Method.GET,
"https://api.github.com/users/octocat",
{ response ->
println("Răspuns: $response")
},
{ error ->
println("Eroare: ${error.message}")
}
)
queue.add(request)
Pentru cererea JSON se folosește JsonObjectRequest, care parsează automat răspunsul în JSONObject. Volley suportă cereri GET și POST. Pentru POST se transmite un JSONObject în corpul cererii.
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("Creat: ${response.getString("id")}")
},
{ println("Eroare: $it") }
)
queue.add(request)
Pentru anularea cererii se folosește metoda cancel() sau anularea în grup după tag. La anulare, Volley nu apelează nici onResponse, nici onErrorResponse, prevenind actualizarea interfeței după părăsirea ecranului. Acest lucru este important pentru prevenirea scurgerilor de memorie în Activity și Fragment.
request.tag = "profile_request"
queue.add(request)
// Anulare la părăsirea ecranului
queue.cancelAll("profile_request")
ImageLoader — este o clasă wrapper peste RequestQueue, optimizată pentru încărcarea imaginilor. Suportă cache în memorie (LruCache) și anulează automat cererile la reutilizarea ImageView în listele RecyclerView. ImageLoader scalează și imaginile la dimensiunea View, economisind memorie.
NetworkImageView — este un View personalizat care se integrează cu ImageLoader și gestionează automat încărcarea: setează un placeholder în timpul încărcării, îl înlocuiește cu eroare la defecțiune și anulează cererea la părăsirea ecranului de către View. DefaultImageUrlLoader încarcă imaginea după URL și o salvează în LruCache pentru reafișare rapidă.
Pentru utilizarea ImageLoader este suficient să creați o instanță prin ImageLoader(queue, ImageCache), unde ImageCache este implementarea interfeței ImageCache cu LruCache în interior. NetworkImageView în XML se leagă de ImageLoader prin metoda setImageUrl(), iar întreaga încărcare are loc complet automat fără cod suplimentar pentru gestionarea placeholder-urilor și erorilor.
Crearea RequestQueue în fiecare Activity — o eroare frecventă care duce la duplicarea firelor și confuzie în cache. Se recomandă crearea RequestQueue o singură dată în Application sau printr-o clasă singleton. În caz contrar, fiecare ecran va avea propriul pool de fire, iar cache-ul va fi stocat separat pentru fiecare coadă.
Ignorarea anulării cererilor la rotirea ecranului. La schimbarea configurației, Activity este recreat, iar callback-urile Activity-ului vechi rămân în memorie. Aceasta duce la scurgeri și la încercarea de a actualiza un View distrus. Anulați întotdeauna cererile în onStop() prin cancelAll() cu un tag specific Activity-ului.
Volley nu suportă HTTP/2 și corutine — aceasta nu este o eroare de utilizare, ci o limitare arhitecturală. Volley a fost creat în 2013 și nu suportă protocoalele moderne și corutinele Kotlin. Pentru proiecte noi, Google recomandă Retrofit + OkHttp. Volley este potrivit doar pentru suportul proiectelor legacy sau al aplicațiilor simple cu cerințe de rețea minimale.
Întrebări frecvente
Volley este învechit pentru proiecte noi — Google nu a actualizat biblioteca din 2017. Pentru aplicații moderne utilizați Retrofit + OkHttp sau Ktor Client. Volley poate fi aplicat doar pentru suportul codului legacy existent sau în proiecte educaționale simple cu sarcini de rețea minimale.
Lipsa suportului pentru tehnologii moderne: HTTP/2, corutine Kotlin, multi-platformă și serializare tipizată. Volley folosește JSONObject și JSONArray fără tipuri, ceea ce duce la erori runtime la nepotrivirea structurii JSON cu așteptările.
Prin ImageLoader și NetworkImageView. ImageLoader folosește LruCache pentru cache-ul imaginilor în memorie și anulează automat cererile la reutilizarea View. NetworkImageView afișează un placeholder în timpul încărcării și îl înlocuiește cu imaginea gata sau un indicator de eroare.
Tehnic da — printr-un wrapper suspendCoroutine { } peste callback-urile Volley. Dar acest lucru nu oferă avantaje, deoarece Volley nu suportă anularea prin anularea corutinei și nu lucrează direct cu Dispatchers.IO. Mai bine folosiți Ktor Client cu suport nativ pentru corutine.
Timeout-ul se configurează prin RetryPolicy. Implicit DefaultRetryPolicy folosește un timeout de 2,5 secunde și o reîncercare. Modificarea parametrilor: request.retryPolicy = DefaultRetryPolicy(10000, 1, 1.0f) — 10 secunde timeout, o încercare.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și