OkHTTP
OkHTTP este un proiect open-source, dezvoltat sub licență Apache, punând la dispoziția utilizatorilor o bibliotecă Java pentru accesarea de resurse prin intermediul protocolului HTTP.
Pentru ca metodele din API-ul OkHTTP Components să poată fi utilizate
într-o aplicație Android este necesar să se specifice catre sistemul de build,
în fișierul build.gradle din app:
...
dependencies {
...
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0'
}
...
De asemenea, in android manifest trebuie sa punem permisiunea de network
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission
android:name="android.permission.INTERNET"/>
...
Pentru a evita blocarea thread-ului main, oricare din apelurile catre API-ul de HTTP va trebui executat pe un thread secundar. Va reamintim o varianta cu un Thread si un handler pentru comunicare.
public class MainActivity extends AppCompatActivity {
// Handler to communicate with UI thread
private Handler mainHandler = new Handler(Looper.getMainLooper());
private TextView resultTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resultTextView = findViewById(R.id.resultTextView);
// Start HTTP request when a button is clicked
Button fetchButton = findViewById(R.id.fetchButton);
// When the button is pressed, make the HTTP request
fetchButton.setOnClickListener(v -> makeHttpRequest());
}
private void makeHttpRequest() {
// We create a new thread, and inside we will run the code for the HTTP API.
new Thread(() -> {
try {
// make request
mainHandler.post(() -> {
// Here we can run code on the main thread, and use variables
// defined in the activity such as restulTextView
resultTextView.setText(result);
});
} catch (Exception e) {
// Handle error on main thread
mainHandler.post(() -> {
resultTextView.setText("Error: " + e.getMessage());
});
}
}).start();
}
}
class MainActivity : AppCompatActivity() {
// Handler to communicate with UI thread
private val mainHandler = Handler(Looper.getMainLooper())
private lateinit var resultTextView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
resultTextView = findViewById(R.id.resultTextView)
// Start HTTP request when a button is clicked
val fetchButton = findViewById<Button>(R.id.fetchButton)
// When the button is pressed, make the HTTP request
fetchButton.setOnClickListener { makeHttpRequest() }
}
private fun makeHttpRequest() {
// We create a new thread, and inside we will run the code for the HTTP API.
Thread {
try {
// make request
mainHandler.post {
// Here we can run code on the main thread, and use variables
// defined in the activity such as restulTextView
resultTextView.text = result
}
} catch (e: Exception) {
// Handle error on main thread
mainHandler.post {
resultTextView.text = "Error: ${e.message}"
}
}
}.start()
}
}
GET. Urmatorul exemplu prezinta o cere simpla de tip GET.
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://wi-fi.cs.pub.ro/expr/expr_get.php?operation=times&t1=9&t2=2")
.build();
try (Response response = client.newCall(request).execute()) {
// Se verifică dacă cererea a avut succes (ex: cod de status 200 OK)
if (response.isSuccessful() && response.body() != null) {
// Se extrage conținutul răspunsului sub formă de text (String)
String content = response.body().string();
/* aici se poate procesa răspunsul obținut */
Log.i(Constants.TAG, content);
} else {
// Se gestionează cazul de eroare (ex: 404 Not Found, 500 Server Error)
Log.e(Constants.TAG, "Cererea nu a avut succes. Cod: " + response.code());
}
} catch (IOException e) {
Log.e(Constants.TAG, "Cererea de rețea a eșuat: " + e.getMessage());
if (Constants.DEBUG) {
e.printStackTrace();
}
}
val client = OkHttpClient()
val request = Request.Builder()
.url("https://wi-fi.cs.pub.ro/expr/expr_get.php?operation=times&t1=9&t2=2")
.build()
try {
client.newCall(request).execute().use { response ->
// Se verifică dacă cererea a avut succes (ex: cod de status 200 OK)
if (response.isSuccessful && response.body != null) {
// Se extrage conținutul răspunsului sub formă de text (String)
val content = response.body!!.string()
/* aici se poate procesa răspunsul obținut */
Log.i(Constants.TAG, content)
} else {
// Se gestionează cazul de eroare (ex: 404 Not Found, 500 Server Error)
Log.e(Constants.TAG, "Cererea nu a avut succes. Cod: ${response.code}")
}
}
} catch (e: IOException) {
Log.e(Constants.TAG, "Cererea de rețea a eșuat: ${e.message}")
if (Constants.DEBUG) {
e.printStackTrace()
}
}
În situația în care se dorește transmiterea de parametri către serverul web, aceștia trebuie incluși în URL (în clar), fără a se depăși limita de 2048 de caractere și folosind numai caractere ASCII:
Request request = new Request.Builder()
.url("http://www.server.com?attribute1=value1&...&attributen=valuen")
.build();
val request = Request.Builder()
.url("http://www.server.com?attribute1=value1&...&attributen=valuen")
.build()
POST. Urmatorul exemplu prezinta o cere simpla de tip POST.
OkHttpClient client = new OkHttpClient();
/* 1. Lista de perechi tip (atribut, valoare) care vor contine
informatiile transmise de client pe baza carora serverul
va genera continutul, de exemplu (user, eim), (parola, 123)*/
FormBody formBody = new FormBody.Builder()
.add("attribute1", "value1")
// ...
.add("attributen", "valuen")
.build();
// 2. Se construiește cererea POST, specificând URL-ul și corpul cererii.
Request request = new Request.Builder()
.url("http://www.server.com")
.post(formBody)
.build();
// 3. Se execută cererea și se procesează răspunsul.
// Acest apel este SINCRON și trebuie executat pe un fir de execuție secundar (background thread).
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful() && response.body() != null) {
// Se extrage conținutul răspunsului sub formă de text.
String content = response.body().string();
// Aici se poate procesa răspunsul (content).
Log.i(Constants.TAG, content);
} else {
// Se gestionează cazul de eroare (ex: 404 Not Found, 500 Server Error).
Log.e(Constants.TAG, "Cererea nu a avut succes. Cod: " + response.code());
}
} catch (IOException e) {
// Se gestionează erorile de rețea (ex: fără conexiune, timeout).
Log.e(Constants.TAG, "Cererea de rețea a eșuat: " + e.getMessage());
if (Constants.DEBUG) {
e.printStackTrace();
}
}
val client = OkHttpClient()
/* 1. Lista de perechi tip (atribut, valoare) care vor contine
informatiile transmise de client pe baza carora serverul
va genera continutul, de exemplu (user, eim), (parola, 123)*/
val formBody = FormBody.Builder()
.add("attribute1", "value1")
// ...
.add("attributen", "valuen")
.build()
// 2. Se construiește cererea POST, specificând URL-ul și corpul cererii.
val request = Request.Builder()
.url("http://www.server.com")
.post(formBody)
.build()
// 3. Se execută cererea și se procesează răspunsul.
// Acest apel este SINCRON și trebuie executat pe un fir de execuție secundar (background thread).
try {
client.newCall(request).execute().use { response ->
if (response.isSuccessful && response.body != null) {
// Se extrage conținutul răspunsului sub formă de text.
val content = response.body!!.string()
// Aici se poate procesa răspunsul (content).
Log.i(Constants.TAG, content)
} else {
// Se gestionează cazul de eroare (ex: 404 Not Found, 500 Server Error).
Log.e(Constants.TAG, "Cererea nu a avut succes. Cod: ${response.code}")
}
}
} catch (e: IOException) {
// Se gestionează erorile de rețea (ex: fără conexiune, timeout).
Log.e(Constants.TAG, "Cererea de rețea a eșuat: ${e.message}")
if (Constants.DEBUG) {
e.printStackTrace()
}
}
Prelucrarea raspunsurilor. Prelucrarea unui răspuns HTTP se poate realiza:
- prin prelucrarea obiectului de tip Response din OkHttp, utilizând fluxuri de intrare/ieșire:
// Presupunem că 'pageResponse' este un obiect valid de tip okhttp3.Response obținut dintr-un apel de rețea.
StringBuilder result = new StringBuilder();
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(pageResponse.body().byteStream()))) {
int currentLineNumber = 0;
String currentLineContent;
while ((currentLineContent = bufferedReader.readLine()) != null) {
currentLineNumber++;
result.append(currentLineNumber).append(": ").append(currentLineContent).append("\n");
}
Log.i(Constants.TAG, result.toString());
} catch (IOException exception) {
Log.e(Constants.TAG, "A apărut o eroare la citirea răspunsului: " + exception.getMessage());
if (Constants.DEBUG) {
exception.printStackTrace();
}
}
// Presupunem că 'pageResponse' este un obiect valid de tip okhttp3.Response obținut dintr-un apel de rețea.
val result = StringBuilder()
try {
BufferedReader(InputStreamReader(pageResponse.body()!!.byteStream())).use { bufferedReader ->
var currentLineNumber = 0
var currentLineContent: String?
while (bufferedReader.readLine().also { currentLineContent = it } != null) {
currentLineNumber++
result.append("$currentLineNumber: $currentLineContent\n")
}
Log.i(Constants.TAG, result.toString())
}
} catch (exception: IOException) {
Log.e(Constants.TAG, "A apărut o eroare la citirea răspunsului: ${exception.message}")
if (Constants.DEBUG) {
exception.printStackTrace()
}
}
- utilizând metoda
string()a obiectuluiResponseBodypentru a obține direct conținutul ca String - mai multe tehnici de rezolvare cu OkHTTP.