• 20 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 12/12/2019

Améliorez la RecyclerView

Vous l'aurez remarqué, l'apparence de notre RecyclerView pourrait être améliorée ! Il serait bien de pouvoir récupérer la photo d'avatar de chaque utilisateur ainsi que d'implémenter un "Pull To Refresh" permettant aux utilisateurs de pouvoir réactualiser le contenu du RecyclerView.

Eh bien c'est justement ce que nous allons faire immédiatement... ;)

Personnalisez la RecyclerView

Reprenez votre application NetApp (disponible également à ce commit). Pour cela, nous allons modifier le fichier XML représentant chaque ligne de notre RecyclerView. Le but est d'afficher l'avatar de chaque utilisateur, ainsi que l'adresse de son Github.

Layout XML fragment_main_item.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="20dip">

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center">

        <ImageView
            android:id="@+id/fragment_main_item_image"
            android:layout_width="50dip"
            android:layout_height="50dip"
            android:layout_margin="5dip"/>

        <TextView
            android:id="@+id/fragment_main_item_title"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="22sp"
            android:textStyle="bold"/>

    </LinearLayout>

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center">
        <TextView
            android:id="@+id/fragment_main_item_website"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textStyle="italic"/>

    </LinearLayout>

</LinearLayout>

Explications : Nous avons ici simplement ajouté dans notre XML un second TextView ainsi qu'une ImageView, le tout organisé grâce à des LinearLayout. Rien de bien compliqué !

Comme vous vous en doutez, nous allons maintenant modifier le ViewHolder correspondant, afin de mettre à jour nos nouvelles vues créées (TextView et ImageView).

En revanche, un petit problème risque de se poser : Comment afficher dans notre ImageView, une image distante accessible via une URL ? Eh bien en fait assez facilement, grâce à une superbe librairie : Glide. Cette dernière va effectuer toute seule la récupération de l'image à partir d'une URL en arrière-plan, puis l'afficher dans une ImageView que vous lui aurez spécifiée.

Afin de l'installer, nous allons comme d'habitude utiliser Gradle notre gestionnaire de dépendances.

Extrait de build.gradle :

dependencies {
    ...
    implementation 'com.github.bumptech.glide:glide:4.2.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.2.0'
}

Modifions maintenant le code de notre ViewHolder afin de pouvoir mettre à jour les vues précédemment créées.

Classe GithubUserViewHolder.java :

public class GithubUserViewHolder extends RecyclerView.ViewHolder {

    @BindView(R.id.fragment_main_item_title) TextView textView;
    // 1 - Adding a TextView and an ImageView
    @BindView(R.id.fragment_main_item_website) TextView texViewWebsite;
    @BindView(R.id.fragment_main_item_image) ImageView imageView;

    public GithubUserViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

    public void updateWithGithubUser(GithubUser githubUser, RequestManager glide){
        this.textView.setText(githubUser.getLogin());
        // 2 - Update TextView & ImageView
        this.texViewWebsite.setText(githubUser.getHtmlUrl());
        glide.load(githubUser.getAvatarUrl()).apply(RequestOptions.circleCropTransform()).into(imageView);
    }
}

Explications : Nous avons répertorié les deux vues que nous venons d'ajouter en XML (Un TextView et une ImageView). Nous avons également modifié notre méthode  updateWithGithubUser()  afin de lui ajouter en paramètre un objet Glide (RequestManager), qui nous permettra de télécharger l'avatar de chaque utilisateur, la transformer en un cercle plus joli, puis l'afficher dans notre ImageView.

Effectuons également la modification liée au passage de notre objet Glide dans notre Adapter ainsi que dans notre contrôleur MainFragment...

Extrait de GithubUserAdapter.java : 

public class GithubUserAdapter extends RecyclerView.Adapter<GithubUserViewHolder> {

    // 1 - Declaring a Glide object
    private RequestManager glide;

    // 2 - Updating our constructor adding a Glide Object
    public GithubUserAdapter(List<GithubUser> githubUsers, RequestManager glide) {
        this.githubUsers = githubUsers;
        this.glide = glide;
    }

    ...

    @Override
    public void onBindViewHolder(GithubUserViewHolder viewHolder, int position) {
        // - 3 Passing the Glide object to each ViewHolder
        viewHolder.updateWithGithubUser(this.githubUsers.get(position), this.glide);
    }

    ...
}

Explications : Nous modifions notre Adapter afin de lui passer la référence d'une instance de Glide, que nous allons créer par la suite dans notre Fragment. Nous mettrons ensuite à disposition cette référence à chaque ViewHolder.

Modifions maintenant notre fragment MainFragment.

Extrait de MainFragment :

public class MainFragment extends Fragment {
    
    ...

    // -----------------
    // CONFIGURATION
    // -----------------

    private void configureRecyclerView(){
        ...
        this.adapter 
        = new GithubUserAdapter(this.githubUsers, Glide.with(this));
        ...
    }

   ...
}

Explications : Comme vous pouvez le voir, une instance de Glide se créée assez facilement. Cependant cette dernière a besoin d'un contexte (Context) en paramètre afin de parfaitement se synchroniser avec le cycle de vie de votre fragment/activité.

Et voilà ! Exécutons maintenant notre application NetApp. Le design est plutôt réussi non ? :D

Résultat
Résultat

Ajouter un "Pull To Refresh"

La fonctionnalité "Pull To Refresh" est quelque chose de largement utilisé par les utilisateurs d'Android sur énormément d'applications. C'est devenu presque un réflexe pour beaucoup de personnes afin d'actualiser le contenu de leurs applications.

Dans le but de faciliter l'implémentation de cette fonctionnalité, Android a ajouté dans sa librairie de support-v4, la classe SwipeRefreshLayout.

Pour commencer, nous allons d'abord modifier le layout contenant notre RecyclerView.

Layout fragment_main.xml :

<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_main_swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <android.support.v7.widget.RecyclerView
            android:id="@+id/fragment_main_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

</android.support.v4.widget.SwipeRefreshLayout>

Explications : Nous avons ici englobé le RecyclerView dans un SwipeRefreshLayout, qui va nous permettre d'activer plus facilement la fonctionnalité "Pull To Refresh" dans notre RecyclerView.

Puis nous allons modifier notre contrôleur, MainFragment, afin de configurer correctement le SwipeRefreshLayout.

Extrait de MainFragment.java :

public class MainFragment extends Fragment {

    ...
    // 1 - Declare the SwipeRefreshLayout
    @BindView(R.id.fragment_main_swipe_container) SwipeRefreshLayout swipeRefreshLayout; 

    ...

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ...
        // 4 - Configure the SwipeRefreshLayout
        this.configureSwipeRefreshLayout(); 
        ...
    }

    ...
    
    // 2 - Configure the SwipeRefreshLayout
    private void configureSwipeRefreshLayout(){
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                executeHttpRequestWithRetrofit();
            }
        });
    }

    ...

    private void updateUI(List<GithubUser> users){
        // 3 - Stop refreshing and clear actual list of users
        swipeRefreshLayout.setRefreshing(false);
        githubUsers.clear(); 
        githubUsers.addAll(users);
        adapter.notifyDataSetChanged();
    }
}

Explications : Dans ce fragment, nous allons simplement configurer notre SwipeRefreshLayout en lui ajoutant un listener qui exécutera notre stream habituelle qui elle rafraichira nos données.

  • Ligne 1 : On déclare notre SwipeRefreshLayout.

  • Ligne 2 : On crée une méthode qui nous permettra de configurer notre SwipeRefreshLayout et surtout de lui ajouter un listener. Ce dernier sera lancé quand l'utilisateur exécutera un "Pull To Refresh" et déclenchera la méthode  onRefresh()  qui elle lancera notre stream habituelle.

  • Ligne 3 : On pense également à arrêter l'animation du SwipeRefreshLayout une fois que notre requête réseau s'est correctement terminée (  setRefreshing(false)  ). Puis, on efface à chaque fois complètement la précédente liste d'utilisateurs (  githubUsers.clear()  ) afin d'éviter de dupliquer celle-ci à cause du  .addAll() .

  • Ligne 4 : Et enfin, on n'oublie pas d'appeler la méthode de configuration du SwipeRefreshLayout dans le  onCreateView()  de notre fragment.

Et voilà ! Lancez maintenant votre application et testez la fonctionnalité "Pull To Refresh". Comment la trouvez-vous ? :D

Représentation
Représentation
Exemple de certificat de réussite
Exemple de certificat de réussite