Nous allons construire maintenant une application Android permettant à un utilisateur de se connecter à un serveur distant en fournissant un nom d'utilisateur et un mot de passe comme dans un précédent article : Connexion à une API REST depuis Android mais cette fois-ci en utilisant la bibliothèque Volley. Lorsque l'utilisateur clique sur le bouton de connexion, une requête POST est envoyée au serveur distant avec le nom d'utilisateur et le mot de passe fournis. Le serveur distant vérifie si les informations d'identification sont valides et renvoie une réponse en conséquence.
Volley est une bibliothèque de traitement de réseau pour Android qui simplifie la communication entre les applications Android et les serveurs. Elle est développée par Google et a été introduite lors de la conférence Google I/O en 2013.
Volley est particulièrement utile pour les développeurs qui doivent récupérer des données à partir de serveurs distants, car elle gère automatiquement les tâches en arrière-plan, telles que la mise en cache des données, la gestion des erreurs et la gestion des files d'attente de requêtes.
La bibliothèque Volley est également très légère et rapide, ce qui la rend adaptée pour les applications mobiles avec des exigences de performance élevées.
En plus de fournir une interface simple pour la communication réseau, Volley fournit également un support pour l'analyse des données JSON, la gestion des images et la prise en charge des requêtes multi-part.
En résumé, Volley est une bibliothèque Android extrêmement utile pour les développeurs qui souhaitent faciliter la communication entre leurs applications et les serveurs distants tout en améliorant la performance de leur application.
Pour utiliser la bibliothèque Volley
, vous pouvez ajouter la dépendance suivante à votre fichier build.gradle
:
implementation 'com.android.volley:volley:1.2.0'
Dans le code suivant la bibliothèque Volley est utilisée pour gérer les requêtes réseau. La méthode loginRequest()
est responsable de créer et d'exécuter une requête POST à l'URL du serveur distant. Cette méthode utilise une instance de la classe StringRequest
pour envoyer une requête POST et récupérer la réponse du serveur.
Le code utilise également une boîte de dialogue de progression pour indiquer à l'utilisateur que le processus de connexion est en cours et un toast
pour afficher les messages d'erreur ou de succès.
Enfin, le code comprend également la gestion des exceptions pour traiter les erreurs de connexion au serveur ou les réponses de serveur inattendues.
Voici le code complet qui utilise la bibliothèque Volley pour effectuer une requête de connexion à un serveur distant.
package com.maestrislyon.simpleloginpage;
import androidx.appcompat.app.AppCompatActivity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
EditText username, password;
Button login;
String userVar, passVar;
ProgressDialog progressDialog;
RequestQueue requestQueue;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
username = findViewById(R.id.username);
password = findViewById(R.id.password);
login = findViewById(R.id.login);
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Logging you in... Please wait");
progressDialog.setCancelable(false);
requestQueue = Volley.newRequestQueue(MainActivity.this);
login.setOnClickListener(view -> {
userVar = username.getText().toString();
passVar = password.getText().toString();
if (userVar.equals("")) {
Toast.makeText(getApplicationContext(), "Username cannot be blank", Toast.LENGTH_SHORT).show();
} else if (passVar.equals("")) {
Toast.makeText(getApplicationContext(), "password cannot be blank", Toast.LENGTH_SHORT).show();
} else {
progressDialog.show();
loginRequest();
}
});
}
private void loginRequest() {
String loginUrl = "https://temp.itds.fr/login_tst.php";
StringRequest stringRequest = new StringRequest(Request.Method.POST, loginUrl,
response -> {
progressDialog.dismiss();
try {
JSONObject jsonObject = new JSONObject(response);
int status = jsonObject.getInt("status");
if (status == HttpURLConnection.HTTP_OK) {
username.setText("");
password.setText("");
Toast.makeText(MainActivity.this, "Login successful", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Incorrect username or password", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "Failed to parse server response", Toast.LENGTH_LONG).show();
}
},
error -> {
progressDialog.dismiss();
error.printStackTrace();
Toast.makeText(MainActivity.this, "Failed to connect to server. Please check your internet connection and try again.", Toast.LENGTH_LONG).show();
}
) {
@Override
protected Map getParams() {
Map params = new HashMap<>();
params.put("email", userVar);
params.put("password", passVar);
return params;
}
};
progressDialog.show();
requestQueue.add(stringRequest);
}
}
Expressions "Lambda"
Une expression lambda est une manière concise d'écrire une fonction en Java.
Elle est définie par une flèche (->) et permet de définir une fonction sans avoir à déclarer explicitement une classe.
Dans le code que vous avez partagé, l'utilisation d'une expression lambda dans la ligne 53 remplace l'usage d'une classe anonyme pour définir un écouteur d'événement pour le bouton de connexion.
Au lieu de créer comme dans notre article précedant une classe anonyme qui implémente l'interface View.OnClickListener
, comme ceci :
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
userVar = username.getText().toString();
passVar = password.getText().toString();
if (userVar.equals("")) {
Toast.makeText(getApplicationContext(), "Username cannot be blank", Toast.LENGTH_SHORT).show();
} else if (passVar.equals("")) {
Toast.makeText(getApplicationContext(), "password cannot be blank", Toast.LENGTH_SHORT).show();
} else {
progressDialog.show();
loginRequest();
}
}
});
On peut utiliser une expression lambda pour définir l'écouteur d'événement de manière plus concise :
login.setOnClickListener(view -> {
userVar = username.getText().toString();
passVar = password.getText().toString();
if (userVar.equals("")) {
Toast.makeText(getApplicationContext(), "Username cannot be blank", Toast.LENGTH_SHORT).show();
} else if (passVar.equals("")) {
Toast.makeText(getApplicationContext(), "password cannot be blank", Toast.LENGTH_SHORT).show();
} else {
progressDialog.show();
loginRequest();
}
});
Cela permet de réduire la quantité de code nécessaire pour définir l'écouteur d'événement, et peut rendre le code plus lisible et plus facile à comprendre.
Exactement pareil, la classe Response.Listener
peut être remplacée par une expression lambda.
Dans ce cas, la classe Response.Listener
est utilisée pour définir une méthode onResponse()
qui sera appelée lorsqu'une réponse sera reçue suite à une requête HTTP. Au lieu de créer une nouvelle instance de cette classe à chaque fois que la méthode loginRequest()
est appelée, il est possible d'utiliser une expression lambda pour définir directement la méthode onResponse()
. Cela permet de simplifier le code et de le rendre plus lisible.
Donc on remplace ce code qui utilise une classe Response.Listener :
StringRequest stringRequest = new StringRequest(Request.Method.POST, loginUrl, new Response.Listener < String > () {
@Override
public void onResponse(String response) {
progressDialog.dismiss();
try {
JSONObject jsonObject = new JSONObject(response);
int status = jsonObject.getInt("status");
if (status == HttpURLConnection.HTTP_OK) {
username.setText("");
password.setText("");
Toast.makeText(MainActivity.this, "Login successful", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Incorrect username or password", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "Failed to parse server response", Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
progressDialog.dismiss();
error.printStackTrace();
Toast.makeText(MainActivity.this, "Failed to connect to server. Please check your internet connection and try again.", Toast.LENGTH_LONG).show();
}
}) {
@Override
protected Map < String, String > getParams() throws AuthFailureError {
Map < String, String > params = new HashMap < > ();
params.put("email", userVar);
params.put("password", passVar);
return params;
}
};
...par le code qui utilise une expression lambda pour définir la méthode onResponse()
:
StringRequest stringRequest = new StringRequest(Request.Method.POST, loginUrl,
response -> {
progressDialog.dismiss();
try {
JSONObject jsonObject = new JSONObject(response);
int status = jsonObject.getInt("status");
if (status == HttpURLConnection.HTTP_OK) {
username.setText("");
password.setText("");
Toast.makeText(MainActivity.this, "Login successful", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Incorrect username or password", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "Failed to parse server response", Toast.LENGTH_LONG).show();
}
},
error -> {
progressDialog.dismiss();
error.printStackTrace();
Toast.makeText(MainActivity.this, "Failed to connect to server. Please check your internet connection and try again.", Toast.LENGTH_LONG).show();
}
) {
@Override
protected Map < String, String > getParams() {
Map < String, String > params = new HashMap < > ();
params.put("email", userVar);
params.put("password", passVar);
return params;
}
};
Dans cet exemple, les méthodes onResponse()
et onErrorResponse()
sont définies à l'aide d'expressions lambda. Comme nous l'avons déjà précisé, cela permet de réduire la quantité de code et de rendre le code plus lisible.
La durée d'affichage des messages "Toast"
Pour augmenter la durée d'affichage des messages "Toast", vous pouvez utiliser la méthode setDuration(int duration)
de l'objet Toast
. Cette méthode prend en argument une constante de durée (Toast.LENGTH_SHORT
ou Toast.LENGTH_LONG
) ou une durée personnalisée en millisecondes.
Par exemple, pour afficher un message "Toast" pendant 5 secondes, vous pouvez utiliser la méthode setDuration(5000)
comme ceci :
Toast.makeText(MainActivity.this, "Login successful", 5000).show();
Cela affichera le message "Login successful" pendant 5 secondes au lieu de la durée par défaut.
La constante Toast.LENGTH_SHORT
affiche le message pendant une courte durée, généralement 2 secondes, tandis que Toast.LENGTH_LONG
affiche le message pendant une durée plus longue, généralement 3,5 secondes.
Vous pouvez choisir la durée qui convient le mieux à votre application et à l'expérience utilisateur que vous souhaitez offrir.
Conclusion
En conclusion, voici un parcours détaillé du code.
La première étape consiste à importer les classes nécessaires à l'application. La classe AppCompatActivity
est importée à partir de la bibliothèque AndroidX, ce qui permet à l'application de prendre en charge les versions récentes d'Android. Les autres classes importées permettent de créer des éléments d'interface utilisateur, d'envoyer des requêtes réseau et de manipuler des objets JSON.
Ensuite, la classe MainActivity
est définie. Cette classe étend la classe AppCompatActivity
et remplace la méthode onCreate()
. Cette méthode est appelée lorsque l'activité est créée et elle initialise les éléments de l'interface utilisateur et les événements de bouton.
Dans la méthode onCreate()
, les éléments de l'interface utilisateur sont initialisés en utilisant la méthode findViewById()
. Cette méthode trouve l'élément de l'interface utilisateur spécifié en utilisant son identifiant R.id
et renvoie une référence à l'objet EditText
ou Button
approprié.
Un ProgressDialog
est créé pour informer l'utilisateur que le processus de connexion est en cours. Le ProgressDialog est configuré avec un message et défini comme non annulable.
Une RequestQueue
est créée à l'aide de la classe Volley. Cette classe gère la file d'attente des requêtes réseau et est utilisée pour envoyer des requêtes HTTP.
Lorsque l'utilisateur clique sur le bouton de connexion, l'événement onClickListener
est déclenché. Cette méthode vérifie si l'utilisateur a entré un nom d'utilisateur et un mot de passe valides. Si l'un des deux champs est vide, un message d'erreur est affiché à l'utilisateur. Sinon, le ProgressDialog est affiché et la méthode loginRequest()
est appelée.
La méthode loginRequest()
crée une StringRequest
à l'aide de l'URL du serveur, de la méthode POST, de la méthode onResponse()
et de la méthode onErrorResponse()
. La méthode getParams()
est également définie dans la StringRequest
et est utilisée pour spécifier les paramètres POST de la requête. Les paramètres POST comprennent l'adresse e-mail et le mot de passe de l'utilisateur.
Lorsque la réponse du serveur est reçue, la méthode onResponse()
est appelée. Cette méthode analyse le JSON de réponse pour vérifier si la connexion a réussi. Si la connexion a réussi, un message de réussite est affiché à l'utilisateur. Sinon, un message d'erreur est affiché.
Si la requête échoue, la méthode onErrorResponse()
est appelée. Cette méthode affiche un message d'erreur à l'utilisateur pour lui indiquer que la connexion au serveur a échoué.
Enfin, le ProgressDialog est affiché et la StringRequest
est ajoutée à la RequestQueue
pour être envoyée au serveur.