Maintenant que nos utilisateurs sont authentifiés dans notre application Android, il serait intéressant qu'ils puissent visualiser leur profil utilisateur et pourquoi pas se déconnecter ou supprimer leur compte.
Suivez-moi, je vous montre ça tout de suite !
Créez l'activité ProfileActivity
Nous allons créer une activité que nous nommerons ProfileActivity dans un package nommé ui. Cet écran nous permettra de récupérer et afficher les informations du profil de l'utilisateur.
Créez une classe appelée ProfileActivity.java que nous allons pré-remplir avec le code suivant afin de nous faire gagner un peu de temps.
Activité ProfileActivity.java :
public class ProfileActivity extends BaseActivity<ActivityProfileBinding> {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupListeners();
}
private void setupListeners(){
binding.updateButton.setOnClickListener(view -> { });
binding.signOutButton.setOnClickListener(view -> { });
binding.deleteButton.setOnClickListener(view -> { });
}
}
Vous remarquerez que cette activité s'étend de BaseActivity pour pouvoir gérer le binding des vues. Le binding des vues vient du layout que j'ai pré-créé pour vous et que vous pouvez retrouver dans le fichier XML res/layout/activity_profile.
Comme pour l'activité précédente, nous avons une fonctionsetupListeners()
afin de gérer les différents events de nos vues.
On pense également à déclarer cette activité dans le manifeste de notre application.
Extrait de AndroidManifest.xml :
<?xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.openclassrooms.firebaseoc"
...
<!-- PROFILE ACTIVITY -->
android:name=".ui.ProfileActivity"
android:label="@string/toolbar_title_login_activity"
android:parentActivityName=".ui.MainActivity"
Maintenant que tout est prêt, nous allons pouvoir commencer à travailler dans de bonnes conditions !
Penchez-vous sur l'architecture de l'application
Avant de continuer, nous allons mettre en place l'architecture de notre application.
Afin de faciliter la lecture et le découpage des fonctionnalités, nous allons utiliser des Manager et des Repository.
Manager et Repository ? Kézako ?
L'objectif de ce cours n'est pas de détailler l'architecture d'une application mobile mais je vais vous présenter rapidement de quoi il s'agit et comment les utiliser.
Repository
Et c'est tout. Aucun traitement n'est fait dans les Repository, ils servent juste à récupérer la data, ni plus ni moins !
Manager
Il s'agit d'une façon de faire parmi tant d'autres, je vous invite à approfondir le sujet des pattern et de l'architecture d'une application mobile si vous le souhaitez.
Et du coup, comment on applique cela à notre application ?
C'est très simple !
Pour l'instant nous allons créer 2 nouveaux sous-packages manager et repository.
Ensuite, nous allons créer dans ses packages respectivement les fichiers UserManager et UserRepository.
Extrait de UserManager :
public class UserManager {
private static volatile UserManager instance;
private UserRepository userRepository;
private UserManager() {
userRepository = UserRepository.getInstance();
}
public static UserManager getInstance() {
UserManager result = instance;
if (result != null) {
return result;
}
synchronized(UserRepository.class) {
if (instance == null) {
instance = new UserManager();
}
return instance;
}
}
}
Extrait de UserRepository :
public final class UserRepository {
private static volatile UserRepository instance;
private UserRepository() { }
public static UserRepository getInstance() {
UserRepository result = instance;
if (result != null) {
return result;
}
synchronized(UserRepository.class) {
if (instance == null) {
instance = new UserRepository();
}
return instance;
}
}
}
Récupérez les informations de l'utilisateur
Maintenant que notre architecture est en place, il faut récupérer les informations personnelles de l'utilisateur actuellement connecté au niveau de notre ProfileActivity fraichement créé.
Avant cela, nous allons créer deux méthodes qui nous serviront à :
récupérer l'utilisateur actuellement connecté à notre application
savoir si ce dernier est correctement authentifié à Firebase.
Vous l'aurez compris, nous allons modifier notre UserRepository et UserManager.
Extrait de UserRepository :
public final class UserRepository {
...
@Nullable
public FirebaseUser getCurrentUser(){
return FirebaseAuth.getInstance().getCurrentUser();
}
}
Extrait de UserManager :
public class UserManager {
...
public FirebaseUser getCurrentUser(){
return userRepository.getCurrentUser();
}
public Boolean isCurrentUserLogged(){
return (this.getCurrentUser() != null);
}
}
Nous utilisons donc cette méthode dans notre repository, chargé de récupérer la data et donc notre user.
La seconde méthode isCurrentUserLogged()
permet, comme son nom l'indique, de savoir si l'utilisateur actuel est connecté ou non.
Cette méthode est implémentée dans le manager et non le repository car il s'agit d'une condition basée sur de la data, il y a donc un traitement afin d'obtenir directement l'information voulue (si l'user est connecté ou non) dans notre UI.
Modifions maintenant notre activité ProfileActivity pour récupérer au démarrage de celle-ci les informations personnelles de l'utilisateur.
Extrait de ProfileActivity :
public class ProfileActivity extends BaseActivity<ActivityProfileBinding> {
private UserManager userManager = UserManager.getInstance();
...
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupListeners();
updateUIWithUserData();
}
...
private void updateUIWithUserData(){
if(userManager.isCurrentUserLogged()){
FirebaseUser user = userManager.getCurrentUser();
if(user.getPhotoUrl() != null){
setProfilePicture(user.getPhotoUrl());
}
setTextUserData(user);
}
}
private void setProfilePicture(Uri profilePictureUrl){
Glide.with(this)
.load(profilePictureUrl)
.apply(RequestOptions.circleCropTransform())
.into(binding.profileImageView);
}
private void setTextUserData(FirebaseUser user){
//Get email & username from User
String email = TextUtils.isEmpty(user.getEmail()) ? getString(R.string.info_no_email_found) : user.getEmail();
String username = TextUtils.isEmpty(user.getDisplayName()) ? getString(R.string.info_no_username_found) : user.getDisplayName();
//Update views with data
binding.usernameEditText.setText(username);
binding.emailTextView.setText(email);
}
}
Explications : Nous avons créé une méthode nommée updateUIWithUserData()
et appelée dans le onCreate()
de l'activité. Cette dernière récupère l'utilisateur actuellement connecté (via la méthode getCurrentUser()
que nous avons précédemment créée dans le manager) et qui nous retourne un utilisateur FirebaseUser.
Grâce à cet objet FirebaseUser, nous pouvons récupérer :
la photo de profil de l'utilisateur grâce à sa méthode getPhotoUrl() et l'afficher dans une ImageView en utilisant la librairie Glide dans la fonction
setProfilePicture()
.l'adresse email de l'utilisateur grâce à sa méthode getEmail() et son nom grâce à sa méthode getDisplayName() afficher le tout dans les TextView correspondants dans la fonction
setTextUserData()
.
Pratique et plutôt simple, non ? Modifions également l'activité MainActivity afin d'afficher, soit l'écran de connexion/inscription, soit l'écran de profil de l'utilisateur quand l'utilisateur clique sur le bouton "Connexion".
Extrait de MainActivity :
public class MainActivity extends BaseActivity<ActivityMainBinding> {
...
private UserManager userManager = UserManager.getInstance();
...
@Override
protected void onResume() {
super.onResume();
updateLoginButton();
}
...
private void setupListeners(){
// Login/Profile Button
binding.loginButton.setOnClickListener(view -> {
if(userManager.isCurrentUserLogged()){
startProfileActivity();
}else{
startSignInActivity();
}
});
}
...
// Launching Profile Activity
private void startProfileActivity(){
Intent intent = new Intent(this, ProfileActivity.class);
startActivity(intent);
}
...
// Update Login Button when activity is resuming
private void updateLoginButton(){
binding.loginButton.setText(userManager.isCurrentUserLogged() ? getString(R.string.button_login_text_logged) : getString(R.string.button_login_text_not_logged));
}
...
}
Explications :
Nous ajoutons le UserManager à notre activity, afin de pouvoir savoir si oui ou non notre utilisateur est connecté. La fonctionstartProfileActivity()
permet de lancer l'activity du Profile.
Sur le clic de notre bouton, on réalise une condition pour savoir si l'utilisateur est connecté et l'envoyer en conséquence sur l'écran de connexion ou l'écran de profil.
Nous avons également la fonction updateLoginButton()
qui est appelée dans la fonction onResume()
afin de pouvoir mettre à jour le bouton lorsque l'activité s'affiche : on affichera "Connexion" si l'utilisateur n'est pas connecté et "Afficher le profil" si ce dernier est connecté.
Lancez l'application et appuyez sur le bouton bleu qui devrait maintenant contenir le texte "Afficher le profil" :
Super, cela semble fonctionner !
Implémentez la déconnexion et la suppression d'un compte
Quand vous développez une application Android, il est important de laisser une certaine liberté à vos utilisateurs afin de ne pas les frustrer. Eh oui, on ne garde jamais tous les nouveaux utilisateurs à vie ! Certains souhaiterons se déconnecter de votre application pour y revenir plus tard, et d'autres carrément supprimer leur compte !
Implémentons ces deux fonctionnalités dans notre application.
Extrait de UserRepository :
public final class UserRepository {
...
public Task<Void> signOut(Context context){
return AuthUI.getInstance().signOut(context);
}
public Task<Void> deleteUser(Context context){
return AuthUI.getInstance().delete(context);
}
}
Extrait de UserManager :
public class UserManager {
...
public Task<Void> signOut(Context context){
return userRepository.signOut(context);
}
public Task<Void> deleteUser(Context context){
return userRepository.deleteUser(context);
}
}
Extrait de ProfileActivity :
public class ProfileActivity extends BaseActivity<ActivityProfileBinding> {
...
private void setupListeners(){
// Sign out button
binding.signOutButton.setOnClickListener(view -> {
userManager.signOut(this).addOnSuccessListener(aVoid -> {
finish();
});
});
// Delete button
binding.deleteButton.setOnClickListener(view -> {
new AlertDialog.Builder(this)
.setMessage(R.string.popup_message_confirmation_delete_account)
.setPositiveButton(R.string.popup_message_choice_yes, (dialogInterface, i) ->
userManager.deleteUser(ProfileActivity.this)
.addOnSuccessListener(aVoid -> {
finish();
}
)
)
.setNegativeButton(R.string.popup_message_choice_no, null)
.show();
});
}
...
}
Explications : Nous commençons par ajouter les fonctions afin de pouvoir exécuter les actions de déconnexion et de suppression d'un compte utilisateur dans nos User Manager et Repository
Ces méthodes utilisent l'objet Singleton AuthUI.getInstance()
de la librairie FirebaseUI. Ce dernier dispose de plusieurs méthodes, dont signOut()
et delete()
, retournant un objet de type Task permettant de réaliser ces appels de manière asynchrone.
Ces tâches Task disposent de plusieurs méthodes de Callback permettant de vérifier si ces dernières se sont correctement terminées.
Dans notre cas, nous implémentons le Callback OnSuccessListener() dans notre activity, afin de pouvoir effectuer une action à la fin du traitement : fermer l'activité courante avec la fonction finish()
.
Exécutez votre application et essayez ces deux fonctionnalités. Vos utilisateurs peuvent désormais se déconnecter et supprimer leur compte depuis votre application Android !
En cas de suppression du compte, vous devriez remarquer que l'utilisateur en question n'apparaît plus dans la base de données des utilisateurs sur l'interface web de Firebase.
En résumé
Pensez à utiliser des Repository et Manager afin de bien séparer les tâches au sein de votre application.
Grace à l'authentification, vous pouvez accéder et modifier les informations de vos utilisateurs : nom, email, photo de profil...