0% ont trouvé ce document utile (0 vote)
70 vues36 pages

Cours Android: Jeremie Guillot

Le document présente un cours sur le développement d'applications Android, dirigé par Jérémie Guillot, un développeur freelance. Il couvre des aspects théoriques et pratiques, y compris la création de projets, l'utilisation d'Android Studio, et le langage Kotlin. Des livrables tels que le cahier des charges, la maquette et le projet final sont également décrits avec des échéances spécifiques.

Transféré par

nous1000vous
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
70 vues36 pages

Cours Android: Jeremie Guillot

Le document présente un cours sur le développement d'applications Android, dirigé par Jérémie Guillot, un développeur freelance. Il couvre des aspects théoriques et pratiques, y compris la création de projets, l'utilisation d'Android Studio, et le langage Kotlin. Des livrables tels que le cahier des charges, la maquette et le projet final sont également décrits avec des échéances spécifiques.

Transféré par

nous1000vous
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

📱

Cours Android
Jeremie Guillot
Support de cours produit par Jérémie Guillot, développeur Android freelance.

Besoin d'une application Android de qualité ? Jérémie Guillot | Freelance Android


Je suis Développeur Indépendant d'applications Android depuis 2015, basé à Lyon, qui apprécie les
projets à impact positif #TechForGood. J'ai aussi un diplôme de psychologie, parfois ça aide. J'ai
travaillé sur plusieurs applications ayant un impact mondial et qui ont été téléchargées plus de 198
[Link]

📨 Contact : [Link]@[Link]
Déroulement du cours
Cours 1 - 4 : Théorie
Cours 5 - 11 : Pratique - Développement d'un projet

Cours 12 : Soutenances

A rendre
CAHIER DES CHARGES : Par mail avant le 10/03, au format PDF.

MAQUETTE : Par mail avant le 17/03, au format PDF ou lien d’invitation (Sketch, Figma, MarvelApp). Le dernier est
surement le plus simple a prendre en main.

PROJET : Par mail au format ZIP ou par invitation sur vos projet Github. Le projet à soutenir le 19 Mai. Il est a rendre le
24 Mai, au soir, au plus tard.

Cahier des charges


Par mail avant le 10/03, au format PDF.

 Contexte et definition du problème

Définir la problématique a laquelle votre application répond, qui est le public cible, comment allez-vous y
répondre, etc.

 Objectif du projet

Qu'est ce qui est attendu a la fin de ce projet ?

 Périmètre du projet

Aussi bien technique (application, site, serveur) qu'utilisateur (pays, age, centre d'intérêt)

 Description fonctionnelle

Pour chaque fonction, vous pouvez adopter une grille précisant : l'objectif, la description de la fonctionnalité,
les contraintes / règles de gestion et le niveau de priorité. Un minimum de 4 fonctionnalités sont attendues.

Titre Definition

Fonction Enregistrer le contact avec le client / créer une nouvelle fiche


Objectif Accéder facilement à un formulaire de saisie comprenant les informations essentielles à demander

Cours Android 1
Titre Definition
L'ouverture d'un formulaire est possible à travers un icone. Il comprend les informations suivantes : Nom,
Description
Prenom, Age, (...), etc.
Contraintes / règles de
Valable que pour les utilisateurs Preniums / Valable apres inscriptions.
gestion

Niveau de priorité Priorité haute / basse

5. Enveloppe budgétaire

Les ressources mobilisées

6. Delais

Exprimez ici la date de réalisation attendue pour votre projet. Avec, pour les cas un peu plus complexes et si
vous souhaitez que je vous ré-oriente en cours, des livrables intermédiaires.

Android Studio
Android Studio est l'IDE officiel pour Android, il est forké a partir de l'IDE de JetBrain. Ainsi, nous disposons dans
Android Studio de tous les avantages comme l'autocompletion, un gestionnaire de fichier, un terminal, etc.
Il est téléchargeable ici :

[Link]

Initilisation du projet

Pour crée un nouveau projet, il suffit de selectionner "Create New Project".

Cours Android 2
Pour vous aider, le Wizard d'Android Studio vous propose déjà des modéles. Dans la plus part des cas, le No Activity et
le Empty Activity suffisent largement au besoin.

Cours Android 3
Les informations obligatoire pour nommer votre projet son un nom et un nom de paquet unique. En effet, ce dernier
reprend la structure d'un site web, a l'envers. Ainsi, si vous utilisez votre nom en nom de domaine à l'envers vous etes
sur d'avoir une application unique.

☝ C'est cet identifiant que prend en compte le Google Play Store pour reconnaitre les applications. Vous pouvez
le retrouver dans l'URL de la page de l'application sur le Store.

Cours Android 4
Si jamais vous ne savez pas quelle version minimal du SDK vous devez choisir, le lien en dessous vous donnera plus
d'information. En effet, vous retrouverez toutes les nouveautés apportés par telle ou telle version (important si votre
application compte utilisé le NFC ou la 5G spécifiquement) et aussi le pourcentage d'utilisateur que vous pourrez
toucher en utiliser cette version. Ici, avec Lollipop vous pourrez toucher 94% des utilisateurs mondiaux. Ce qui est un
beau temps et vous assure de pouvoir toucher la totalité des utilisateurs francais.

Interface d'Android Studio


Au premier lancement, ceci peut faire peur l'interface est relativement bien structuré. Nous allons passé en revue les
parties les plus importantes.

En commencant par le haut, vous retrouverez les commandes les plus importantes pour votre projet :

Build : Vous permez de construire votre projet, de verifier que tout compile correctement.

Device : Vous permez de selectioner le device que vous souhaitez. Vous pouvez vous connecter a votre propre
telephone ou a un emulateur.

Run : Vous permez de lancer votre application, aprés l'avoir compiler.

Debug

Cours Android 5
Attach Debut :

Gradle :

Comment connecter votre telephone en mode developpeur :

[Link]
o%20enable%20developer%20options%2C%20tap,Settings%20%3E%20About%20Phone%20%3E%20Build%20Number

Kotlin
Langage officiel d'Android
Lorsque Kotlin de JetBrain a été annoncé comme un langage de développement officiel pour Android durant la
conférence Google I/O en mai 2017, il est devenu le troisième langage entièrement pris en charge pour Android, en plus
de Java et C.

Aujourd'hui, la majorité du développement se fait dans ce langage et Google développe toutes ses futurs librairies dans
ce language.

Quelque avantages de Kotlin par rapport a Java :

Extension functions, Null-safety, Lambda expressions, Inline functions, Smart casts, String
templates, Properties, Primary constructors, Range expressions, Operator overloading,
Companion objects, Data classes, Coroutines, etc...

Nous en verrons quelques uns durant le cours.

Collections
L'utilisation des collections est beaucoup plus simple qu'avec du Java. Nous allons voir les exemples suivantes la
facilité d'utilisation de Kotlin dans un cas précis. Mais cela peut s'appliquer au language en general.

Cours Android 6
Dans les exemples suivant, tout le code se présente dans une fonction fun main(){} . Pour executer le code si dessous, il
suffit de créer un fichier Kotlin (se terminant par .kt ), de copier le code et une flèche d'execution d'apparaitra a coté
de fun main(){} . Il ne reste plus qu'a cliquer dessus.
Ou vous pouvez lancer l'execution depuis Kotlin Play.

Arrays

fun main() {
// simple initialization
val arrayOfNumbers = arrayOf(2, 3, 5, 6, 10)
val intArray = intArrayOf(2, 3, 5, 10)

val someArray = emptyArray<String>() // same as arrayOf<String>()


val someOtherArray = Array(5) { "" } // allocation with size and initializer

println("The array size is: ${[Link]}")


println("The other array size is: ${[Link]}")

// the difference in array types


println(arrayOfNumbers)
println(intArray)

// accessing values

// printing each value -> iterating


[Link] { println(it) }
[Link] { println(it) }

// indexed iteration
[Link] { index, value ->
println("Value at index $index is $value")
}

// iterating using for loops


for (number in arrayOfNumbers) {
println(number)
}

for (number in intArray) {


println(number)
}

// using indices
val thirdValue = arrayOfNumbers[2] // same as [Link](2)
println("The third value is $thirdValue")
arrayOfNumbers[2] = 100 // we can reassign the values

// helpful functions
println("The last value is: ${[Link]()} and the first is: ${[Link]()}")

val names = arrayOf("Filip", "Babic", "Kotlin", "RayWenderlich")


printValues("First", "Second", "Third", "Fourth")
printValues(*names) // spread operator
}

fun printValues(vararg values: String) {


[Link] { println(it) }
}

Lists

fun main() {
val list = listOf(2, 3, 5, 6, 7)
val arrayList = arrayListOf(2, 3, 5, 6, 7)

println(list)
println(arrayList)

[Link](8)
[Link](9)
[Link](3)
println(arrayList)
}

Cours Android 7
Maps

fun main() {
val httpHeaders = hashMapOf(
"Authorization" to "your-api-key",
"ContentType" to "application/json",
"UserLocale" to "US"
)

[Link] { (key, value) -> println("Value for key $key is $value") } // printing formatted keys and values
println(httpHeaders) // printing a map as an object

httpHeaders["Authorization"] = "something else"


println(httpHeaders)
}

Mutability

data class Worker(


val id: Int,
val name: String
)

fun main() {
val mutableItems = mutableListOf<Worker>()

// adding and removing item


[Link](Worker(id = 5, name = "Filip")) // we can add item
println(mutableItems)
[Link](0) // removing values
println(mutableItems)

// adding a list of items


[Link](
listOf(
Worker(0, "John"),
Worker(1, "Peter"),
Worker(2, "Stephanie")
)
)
println(mutableItems)

// clearing all the items


[Link]()
println(mutableItems)

var items = listOf("First", "Second", "Third")


println(items)

items = listOf("Fourth")
println(items)

val immutableItems = listOf("Immutable item")

// cannot remove or add items


val result = immutableItems - "Immutable item" // this works, since it's creating a new list
println(immutableItems)
println(result)
}

Var & Val


var est comme une variable générale et elle est connue comme une variable mutable dans kotlin et peut être assignée

plusieurs fois.
val est comme une valeur finale et elle est connue comme immuable par Kotlin et peut être initialisée une seule fois.

Ainsi, déclarer une valeur val vous assure d'obtenir un objet non-null.

Null Safety

Cours Android 8
En Kotlin, toutes les variables sont non nulles par défaut. Nous ne pouvons pas attribuer une valeur nulle à une variable
car cela entraînerait une erreur de compilation :

var name: String = "Julie"


name = null //compilation error

Pour définir une variable annulable, nous devons ajouter un point d'interrogation ( ? à la déclaration de type :

var name: String? = "Julie"


name = null //it's ok but Kotlin will warn you when using it
val length = name?.length //without ?. it's a crash
print(length)

Pour appeler une variable qui peut potentiellement être nulle, il faut utiliser un safe call operator ?.

Elvis Operator ?
Nous pouvons utiliser l'opérateur Elvis ?: pour renvoyer une valeur par défaut uniquement si la variable originale a une
valeur nulle. Si l'expression de gauche de l'opérateur Elvis a une valeur non nulle, alors elle est renvoyée. Sinon,
l'expression de droite est renvoyée.

var name : String? = "Julie"


name = null //it's ok but Kotlin will warn you when using it

val length = name?.length ?: 0 // without ?:, length will be null


print(length)

Ici, length est de type Int , on est donc certain que la valeur ne sera jamais null. Si nous n'avions par rajouter
l'opérateur Elvis, nous aurions length est de type Int? et donc potentiellement null a tout instant.

Data Class
Dans ce dernier exemple, nous avons utiliser une data class . Il faut les concevoir comme des classes qui ne sont faites
que pour contenir des données et quelques méthodes basiques.

Cours Android 9
Le compilateur génère automatiquement les membres suivants de toutes les propriétés déclarées dans le constructeur
primaire :

paire equals()/ hashCode()

toString() du formulaire "Worker(0, "John")".

la fonction copy().

Pour assurer la cohérence et le comportement significatif du code généré, les classes de données doivent remplir les
conditions suivantes :

Le constructeur principal doit avoir au moins un paramètre.

Tous les paramètres du constructeur primaire doivent être marqués comme val ou var .

Les data class ne peuvent pas être abstraites, ouvertes, scellées ou internes.

Exercice

data class Student(val name: String, val age: Int, val country: Country)

enum class Country {


FRANCE,
ITALY,
SPAIN
}

fun main() {

val julien = Student("Julien", 15, [Link])


val lucie = Student("Lucie", 13, [Link])
val arthur = Student("Arthur", 23, [Link])
val richard = Student("Richard", 19, [Link])
val bob = Student("Bob", 18, [Link])

val students = listOf(julien, lucie, arthur, richard, bob)

// print the first in the list

// print the last in the list

// print the second last in the list

// print the last French in the list

// print who is an adult

// print who is French

// print the average age

// print the youngest

// print the oldest


}

Correction Kotlin List

Pour en apprendre plus sur Kotlin et de nombreuses autres fonctionnalités, je vous recommande la série de Donn
Felker sur Youtube. Si vous avez deja Android Studio, vous n'avez pas besoin d'autre IDE.

"Hello World" in Kotlin - Your First Kotlin Program


In this lesson, you'll create your first Kotlin "Hello World" [Link] the entire FREE Kotlin
Programming course here: [Link]
[Link]
z&index=4

Néanmoins, les bases présentés ici suffissent pour suivre le cours sur Android.

Cours Android 10
Android Developpment
User Interface
LinearLayouts

Dans cette premiere creation, nous allons voir pour


reproduire une vue de type Tinder. En effet, la
conception est simple. Une image, un texte, deux bouton
: le tout dans deux LinearLayout.

android:orientation="vertical" permet d'orienter un

LinearLayout dans le sens vertical. L'orientation


horizontal existe aussi.

Pour repartir de maniere non equitable, nous utilisons ici


android:weightSum="5" . L'element parent possède un poids

de 5 que la somme des enfants doit attendre, en


declarant le poids d'un enfant ainsi
android:layout_weight="3" .

Pour indiquer une information uniquement a but de


développement, on utilise l'annotation tools:srcCompat .

Correction LinearLayout

ConstraintLayout

Cours Android 11
Nous voulons la majorité concevoir des designs plus
compliqué, c'est ainsi que les ConstraintsLayout sont
utiles.
Ces derniers peuvent être référencés sur les 4 axes :
start , end , top , bottom . Il suffit d'utiliser l'annotation

app:layout_constraintTop_toTopOf="parent" pour contraindre le

dessus de la vue sur le dessus de son parent.


On peut aussi contraindre une vue avec une autre vue.
Ici, app:layout_constraintStart_toEndOf="@id/img_ic_phone" , le
début de la vue est contrainte avec la fin d'une autre.
On remarquera la disposition particulière de l'icône
Modifier.

Source

Avec app:layout_constraintVertical_chainStyle="packed" , on peut gerer la distribution de plusieurs vues enchainer les unes au
autres:

 Spread : Les points de vue sont répartis équitablement

 Spread inside : La première et la dernière vue sont apposées sur les contraintes à chaque extrémité de la chaîne et
le reste est réparti de manière égale

 Spread : Les points de vue sont emballés ensemble

 Weighted : Lorsque la chaîne est paramétrée pour s'étendre ou se déployer à l'intérieur, vous pouvez remplir
l'espace restant en paramétrant une ou plusieurs vues pour qu'elles "match constraints" (0dp)

Correction ConstraintLayout

Cours Android 12
ScaleType
Pour afficher correctement l'image dans l'exemple ci-dessus, nous avons utilisé l'attribut android:scaleType , celui peut
prendre plusieurs valeurs qui dispose sa ressource (principalement une image) dans une position particulière.

Source

Margin & Padding


Concept largement hérité du web, une vue peut décidé
de sa zone d'imperméabilité.

On declare le margin de la manière suivante :


android:layout_marginTop="36dp" . Comme les

ConstraintLayouts, vous pouvez utiliser les orientations


start , end , top , bottom .

Cours Android 13
Le meme concept s'applique pour le padding : android:padding="24dp" . Vous pouvez rajouter les meme orientations que
pour Margin et les ConstraintLayouts. Ici, en ne declarant aucune orientation, ceux sont tous les bords qui sont
impactés.

RecyclerView

RecyclerView permet d'afficher facilement et


efficacement de grands ensembles de données. Vous
fournissez les données et définissez l'aspect de chaque
élément, et la bibliothèque RecyclerView crée
dynamiquement les éléments au moment où ils sont
nécessaires.

Comme son nom l'indique, RecyclerView recycle ces


éléments individuels. Lorsqu'un élément défile hors de
l'écran, RecyclerView ne détruit pas sa vue. Au contraire,
RecyclerView réutilise la vue pour de nouveaux
éléments qui ont défilé à l'écran. Cette réutilisation
améliore considérablement les performances, améliorant
la réactivité de votre application et réduisant la
consommation d'énergie.
Source

Quelques concepts
Plusieurs classes différentes travaillent ensemble pour construire une liste dynamique.

RecyclerView est le ViewGroup qui contient les vues correspondant à vos données. C'est une vue en soi, vous
ajoutez donc <RecyclerView/> dans votre présentation comme vous le feriez pour tout autre élément de l'interface
utilisateur.

Chaque élément individuel de la liste est défini par un objet "view holder". Lorsque le view holder est créé, il n'est
associé à aucune donnée. C'est le RecyclerView qui le lie à ses données. Vous définissez le view holder en
étendant [Link] .

Le RecyclerView demande ces vues, et les lie à leurs données, en appelant des méthodes dans l'adaptateur. Vous
définissez l'adaptateur en étendant [Link] .

Cours Android 14
Le layout manager organise les éléments individuels de votre liste. Vous pouvez utiliser l'un des layout manager
fournis par la bibliothèque RecyclerView, ou vous pouvez définir le vôtre. Les gestionnaires de mise en page sont
tous basés sur la classe abstraite LayoutManager de la bibliothèque.

class CustomAdapter(private val dataSet: Array<String>) :


[Link]<[Link]>() {

/**
* Provide a reference to the type of views that you are using
* (custom ViewHolder).
*/
class ViewHolder(view: View) : [Link](view) {
// Define item view for the ViewHolder's View.
val textView = [Link]([Link])
}

// Create new views (invoked by the layout manager)


override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
// Create a new view, which defines the UI of the list item
val view = [Link]([Link])
.inflate([Link].text_row_item, viewGroup, false)

return ViewHolder(view)
}

// Replace the contents of a view (invoked by the layout manager)


override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {

// Get element from your dataset at this position and replace the
// contents of the view with that element
[Link] = dataSet[position]
}

// Return the size of your dataset (invoked by the layout manager)


override fun getItemCount() = [Link]

<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/element_text"/>

Example of RecyclerView with Listener

Accessibility
On estime a plus de la moitié des utilisateurs de smartphones ayant un problème d'accessibilité, on parle de personne
mal voyante, daltonienne ou tout simplement de personne ayant une moins bonne vue que la moyenne.

Ainsi, il est important d'améliorer a minima votre application pour ses utilisateurs

L'attribut vous permet de définir un texte qui sera lu par TalkBack. TalkBack vous permet d'explorer la vue en utilisant
des gestes, tout en décrivant de manière audible ce qui se trouve à l'écran.

android:contentDescription="@string/add_coffee" //String saved in [Link]

Ainsi, un utilisateur utilisant TalkBack en navigant sur


l'application entendra la phrase définie add_coffee lu à
voix haute. On retrouve l'argument contentDescription sur
les images, les FloatingActionButton, les menus, etc.
Android Studio vous indique lorsqu'il est manquant.

Si jamais votre utilisateur doit rentrer un texte dans un


champ, vous pouvez aussi définir un paramètre labelFor
pour définir ce qui est attendu dans ce champ. La

Cours Android 15
référence attendu est l'EditText qui attend l'input de
l'utilisateur. Elle se place sur le TextView, ici Coffee Limit.

android:labelFor="@id/coffeeLimitValue"

Pour en apprendre plus sur l'accessibilité, je vous


recommande le tutoriel de Victoria Gonda.

Android Accessibility Tutorial: Getting Started


In this Android accessibility tutorial, learn how to
make apps that everyone can use, including people
with vision, motor, or hearing disabilities. Version
[Link]
ccessibility-tutorial-getting-started#toc-anchor-00
8

Localization - Translation
Pour retrouver tous les textes de votre application, il suffit d'aller dans res > strings .

Si vous souhaitez ajouter une traduction a votre application, c'est possible. Il vous suffit de sélectionner Open Editor
sur la capture d'écran précédente et de rajouter un pays comme indiqué si dessous.

Cours Android 16
App Components
Activities & Fragments
LifeCycle
Pour naviguer dans les transitions entre les étapes du
cycle de vie des activités, la classe Activity fournit un
ensemble de six états : onCreate() , onStart() , onResume() ,
onPause() , onStop() et onDestroy() . Le système invoque

chacun de ces rappels lorsqu'une Activity entre dans un


nouvel état.

Source

onCreate() : Votre vue se crée. N'essayez pas appeler une

reference sur une vue avant. Crash assuré.

onResume() : Appelé lorsque toute la vue est prête ou que


l'utilisateur revient dessus.
onPause() : Se déclenche lorsque l'utilisateur quitte la vue,
aussi bien en naviguant ou en sortant avec le bouton
Home.

onDestroy() : Votre vue est complètement détruite. Plus

rien n'est accessible.

Intents
Les Intents sont utilisés pour déclarer une intention dans l'application. Elles peuvent prendre de nombreuses formes
comme : vouloir se rendre d'un point A à B, faire appel à une autre application (partage de texte, d'image, etc.),
planifier une action dans le futur, etc.

Cours Android 17
Passer d'une Activity A à B.

/** Launch another activity */


fun goToDetail() {
val intent = Intent(this, MySecondActivityName::[Link])
startActivity(intent)
}

Passer d'une Activity A à B avec des informations.


On crée un Intent en indiquant l'origine et la destination. Ici, MyDestination est une autre activité.

Intent(this, MyDestination::[Link]) //this refer the origin, here

Pour rajouter des paramètres, on utilise putExtra . Vous pouvez fournir tous les classes natives de Kotlin Int, String,
etc.). Pour les autres, ils faut les Parcer.

putExtra(EXTRA_MESSAGE, message)

Exemple

const val EXTRA_MESSAGE = "[Link]"

/** Called when the user taps the Send button */


fun sendMessage() {
val editText = findViewById<EditText>([Link])
val message = [Link]()
val intent = Intent(this, DisplayMessageActivity::[Link]).apply {
putExtra(EXTRA_MESSAGE, message)
}
startActivity(intent)
}

Pour recuperer les informations une fois à destination, on utilise getStringExtra

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_display_message)

// Get the Intent that started this activity and extract the string
val message = [Link](EXTRA_MESSAGE)
//here you can do whatever you want with the message

Créer une nouvelle destination, une nouvelle activité


En faisant un clic droit sur l'endroit où vous voulez votre nouvelle activité, dirigez-vous vers New > Activity > Empty

Activity . Il ne vous reste plus qu’à donner un nom a votre activité et son design.

Cours Android 18
Gradle
Gradle est un build system fonctionnant sur Android Studio. Si vous venez du monde Java, son équivalent est Maven.
L'écosystème Android permet de nombreuses choses, mais pour nous simplifier la vie ou pour améliorer
considérablement notre application, nous pouvons lui fournir facilement de super-pouvoir. Ainsi, en ajoutant des
dépendances à notre application, nous pouvons facilement implémenter des extensions au code (un lecteur video
puissant, intégrer Zoom, faciliter les appels réseaux, etc).

Vous retrouverez dans le code des exemples a intégrer à Gradle 🔌, , de ce style :


//ExoPlayer - Video Player
implementation '[Link]:exoplayer:2.11.8'

Il faut rajouter cette ligne dans le fichier [Link] Module : .app ) > dependencies .

⚠ Attention de ne pas confondre avec le fichier [Link] Project)

N'oubliez pas de synchroniser Gradle après cet ajout. Il va télécharger en ligne cette nouvelle extension.

Cours Android 19
Networking
Retrofit
La documentation de Retrofit :

Retrofit
Annotations on the interface methods and its parameters indicate how a request will be handled. Request Method Every method must have an HTTP
annotation that provides the request method and relative URL. There are eight built-in annotations: HTTP, GET, POST, PUT, PATCH, DELETE, OPTIONS
and HEAD.
[Link]

Retrofit est une dépendance nous permettant de réaliser facilement des appels réseaux.

🔌 Gradle:
//Network Retrofit
implementation "[Link].retrofit2:retrofit:2.9.0"
implementation '[Link].okhttp3:logging-interceptor:4.9.0'

Dans le Manifest de l'application que vous trouverez vous le dossier manifests, veuillez rajouter la permission suivante :

<uses-permission android:name="[Link]" />

Ainsi, Android nous permettra de passer des appels réseaux sans soucis. Il existe bien évidement d'autre permissions
et certaines qui demandent même l'autorisation de l'utilisateur (accès aux contacts, camera, micro, etc).

Cours Android 20
Ici, un exemple d'un appel GET.

interface ApiClient {
@GET("history")
suspend fun getHistory(): Response<List<HistoricalEventsResponse>>

@GET("/history/{event}")
suspend fun getHistory(@Path("event") eventId: String): HistoricalEventsResponse
}

Moshi
Lorsque l'on reçoit un objet revenant d'un appel réseau, majoritairement sous la forme d'un Json, il nous faut le parser
pour l'intégrer dans l'application. Le parsage de Json est fastidieux, ainsi Moshi nous vient en aide.

🔌 Gradle:
//on the top of the file
plugins {
id 'kotlin-kapt' // add this line only
}

//Serialization - Moshi
implementation("[Link]:moshi-kotlin:1.11.0")
implementation("[Link]:moshi-kotlin-codegen:1.11.0")
implementation "[Link].retrofit2:converter-moshi:2.9.0"
kapt("[Link]:moshi-kotlin-codegen:1.11.0")

Il nous suffit de crée un objet similaire a celui qu'on vient intercepter. Ici, on souhaite parser un retour Json, ainsi on
demande la génération de l'adapter generateAdapter = true qui fera ca pour nous. De plus, on indique l'équivalence de
chaque champ Json avec l'object avec @Json(name = "id") .

@JsonClass(generateAdapter = true)
data class HistoricalEvents(
@Json(name = "id")
val id: Int,
@Json(name = "title")
val title: String,
@Json(name = "details")
val details: String,
@Json(name = "flight_number")
val flightNumber: Int?
)

Par la suite, notre repository consomme simplement notre Api.

class EventsRepository(
private val apiClient: ApiClient
) {
suspend fun getHistoricalEvents() = [Link]()
}

Attention, la définition de l'APIClient est ici manquante.



Elle se retrouve dans la partie sur Hilt, plus bas.

Exemple Retrofit & Hilt avec un appel réseau vers SpaceX API

Architecture
MVVM

Cours Android 21
Le principe le plus important à suivre est la séparation des préoccupations. C'est une erreur courante d'écrire tout
votre code dans une activité ou un fragment. Ces classes basées sur l'interface utilisateur ne doivent contenir que la
logique qui gère les interactions entre l'interface utilisateur et le système d'exploitation. En gardant ces classes aussi
légères que possible, vous pouvez éviter de nombreux problèmes liés au cycle de vie.
Une Activité ou un Fragment contient le rendu visuel de votre vue et aussi il est la premiere interface pour les
interactions de l'utilisateur. Le système d'exploitation Android peut les détruire à tout moment en fonction des
interactions de l'utilisateur ou en raison de conditions système telles qu'une faible mémoire. Pour offrir une expérience
utilisateur satisfaisante et une maintenance de l'application plus facile à gérer, il est préférable de minimiser votre
dépendance à leur égard.

Un objet ViewModel fournit les données pour un composant spécifique de l'Interface Utilisateur UI , tel qu'un
fragment ou une activité, et contient la logique de traitement des données pour communiquer avec le Repository. Par
exemple, le ViewModel peut appeler d'autres composants pour charger les données, et il peut transmettre les
demandes de l'utilisateur pour modifier les données. Le ViewModel ne connaît pas les composants de l'interface
utilisateur, il n'est donc pas affecté par les changements de configuration, comme la recréation d'une activité lors de la
rotation de l'appareil.
Les Repository gèrent les opérations sur les données. Ils fournissent une API propre afin que le reste de l'application
puisse récupérer ces données facilement. Ils savent d'où obtenir les données et ce quoi faire lorsque les données sont
mises à jour. Vous pouvez considérer les Repository comme des médiateurs entre différentes sources de données,
comme les base de données locales, les API ou encore le cache.

Cours Android 22
Documentation

[Link]

Clean Architecture
L'architecture propre sépare votre code d'application en couches et ces couches définissent la Separation of Concerns
à l'intérieur de la base de code.
La clean architecture sous Android se divise en trois parties :

 La Presentation

Cette partie comprend principalement l'état de votre application, les elements visuels et interactions utilisateurs.

 Le Domaine
Partie centrale de l'application, c'est lui qui détient la logique de l'application.

 Le Data

Il s'occupe des données de l'application, il sait où se trouve les informations, en ligne ou local.

Cours Android 23
Ce schéma reprend un parcours utilisateurs qui sélectionnerait un item dans une liste. Les couleurs correspondent aux
Parties présentées au-dessus. La partie mauve fait reference au Navigator, celui qui sait comment emmener
l'utilisateur de A à B, il utilise des Intents.

Source

Dependency Injection
Hilt
Il nous permet de faire de l'injection de dépendance.

Cela consiste à créer dynamiquement (injecter) les dépendances entre les différents objets en s'appuyant sur une
description (fichier de configuration comme NetworkModule , DataModule ) ou de manière programmatique (avec by

Cours Android 24
viewModels() ou @Inject lateinit var analytics: AnalyticsAdapter , par exemple). Ainsi les dépendances entre composants
logiciels ne sont plus exprimées dans le code de manière statique mais déterminées dynamiquement à l'exécution.

Ceci vous permet une maintenance de votre application (seulement l'injector sait comment créer les dépendances),
une réduction des erreurs dans la création d'objet, une meilleur lisibilité et décrire moins de code au final.

Différence entre des dépenses traditionnelles et l'injection

Dans l'image ci-dessus, dans l'exemple de gauche, Main a besoin de plusieurs elements pour fonctionner. Ainsi, soit il
les crée lui même ou en fait la demande explicite. Main peut très bien être une Activity, un ViewModel, un repository,
etc. Dans l'exemple de droite, Main fait la demande a l'Injection de Dépendances de lui fournir ce qu'il a besoin, mais a
aucun moment il ne sait comment les créer.

Documentation

[Link]

Configuration
Dans 🔌 Gradle Project, rajouter dans les dependencies :

def hilt = "2.28-alpha"


classpath "[Link]:hilt-android-gradle-plugin:$hilt"

Dans 🔌 Gradle Module, en dessous android{} , rajouter :

packagingOptions {
exclude("META-INF/*.kotlin_module")
}

Puis dans les dépendances :

//on the top of the file, with the others one


plugins {
id '[Link]' //add only this line
}

dependencies {
//Lifecycle
implementation "[Link]:lifecycle-viewmodel-ktx:2.3.0"

//Hilt
implementation '[Link]:fragment-ktx:1.3.0'
implementation "[Link]:lifecycle-viewmodel-ktx:2.3.0"
implementation "[Link]:lifecycle-extensions:2.2.0"
implementation "[Link]:hilt-lifecycle-viewmodel:1.0.0-alpha03"
implementation '[Link]:hilt-android:2.31-alpha'
kapt '[Link]:hilt-compiler:1.0.0-alpha03'
kapt "[Link]:hilt-android-compiler:2.31.2-alpha"
}

Cours Android 25
On crée une nouvelle classe qui se lancera en premiere dans notre application.

@HiltAndroidApp
class AppApplication : Application() {
}

Et on la rajoute dans le manifest sous l'argument android:name

<manifest xmlns:android="[Link]
package="[Link]">

<application
android:name=".[Link]"
<!-- ... -->
</application>
</manifest>

Description
Une fois la configuration terminée, nous pouvons définir les objects que notre Injector devra s'occuper pour les autre
classe de notre application.
Pour définir un NetworkModule qui contiendra tous nos elements relatifs à nos appels réseaux, ainsi lorsque nous aurons
besoin d'un client pour appeler une Api, il nous suffira simplement de l'ajouter dans le constructeur du Repository. Ici
dans un exemple avec Retrofit

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

@Singleton
@Provides
fun provideRetrofit(): Retrofit {
val API_BASE_URL = "[Link]
val httpClient = OkHttpClient().newBuilder().build()
return [Link]()
.baseUrl(API_BASE_URL)
.addConverterFactory(
[Link](
[Link]().add(KotlinJsonAdapterFactory()).build()
)
)
.client(httpClient)
.build()
}

@Singleton
@Provides
fun provideWhoApi(retrofit: Retrofit): ApiClient {
return [Link](ApiClient::[Link])
}
}

Ici dans un exemple avec un Repository ,

@Module
@InstallIn(SingletonComponent::class)
object DataModule {
@Singleton
@Provides
fun provideEventsRepository(
apiClient: ApiClient,
): EventsRepository {
return EventsRepository(apiClient)
}
}

Cours Android 26
Injection
Une fois que nous avons terminé nos definitions, nous pouvons utiliser nos objects où nous le souhaitons. Pour donner
accès a l'Injector, nous définissons sur nos Activity @AndroidEntryPoint et de meme pour les ViewModels @HiltViewModel .

Ici, une activity.

@AndroidEntryPoint
class ListActivity : AppCompatActivity() {}

Ici, un viewModel.

@HiltViewModel
class ListViewModel @Inject constructor(
private val repository: EventsRepository
) : ViewModel() {}

Pour le ViewModel, nous demandons certains éléments dès sa creation en ajoutant le paramètre @Inject constructor .

Philipp Lackner explique comment utiliser Hilt en video.

Dagger-Hilt in Detail - Full Course


In this video you will learn the essential things about Dagger-Hilt.0000 - Introduction &
Dependencies0211 - Application class0357 - AppModule0907 - Inje...

[Link]

Android Jetpack

Jetpack en 2019.

Jetpack est une suite de bibliothèques destinées à aider les développeurs à suivre les meilleures pratiques, à réduire le
code boilerplate et à écrire un code qui fonctionne de manière cohérente sur toutes les versions d'Android et tous les
appareils afin que les développeurs puissent se concentrer sur le code qui les intéresse.

Cours Android 27
[Link]

➡ Getting Started
Data Persistence
Room

[Link]

Room est composé de plusieurs éléments :

Room Database : l'element qui contient la base de donnée. Apres une simple definition dans Hilt, elle est générée
automatiquement par Android.

Data Access Objects DAO : ceux sont eux qui vont nous permettre de communiquer facilement avec la base de
donnée. (ajoute, supprimer, filtre, etc...)

Entities : ceux sont les objects que nous souhaitons stocker dans notre base de donnée.

Dans 🔌 Gradle app, rajouter :


def room_version = "2.2.6"
implementation "[Link]:room-runtime:$room_version"
kapt "[Link]:room-compiler:$room_version"
implementation "[Link]:room-ktx:$room_version"

Commençons par définir l'objet que nous voulons sauvegarder dans cette base de données.

Cours Android 28
@Entity // define that it's an entity of the database
data class ShoppingItem(
@PrimaryKey val uid: String, // mandatory for all entity, can't be null
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "quantity") val quantity: Int?
)

Par la suite, une fois que nous avons notre objet, nous pouvons créer le DAO qui nous permettra de communiquer avec
lui. On y retrouve des fonctions basiques comme des insertions, des suppressions, etc... mais on peut aussi définir des
requêtes Query) dans le language SQL.

@Dao
interface ShoppingItemDao {
@Query("SELECT * FROM shoppingitem ORDER BY name")
fun getAll(): Flow<List<ShoppingItem>>

//@Query("SELECT * FROM shoppingitem WHERE name LIKE :name") if we wanted to search on full name
@Query("SELECT * FROM shoppingitem WHERE name LIKE '%' || :name || '%'")
fun filterByName(name: String): Flow<List<ShoppingItem>>

@Insert(onConflict = [Link])
suspend fun insert(vararg item: ShoppingItem)

@Delete
suspend fun delete(shoppingItem: ShoppingItem)
}

En avant dernière étape, il nous faut définir notre base de donnée, ce qu'elle contient et comment communiquer avec
elle, ici a travers un DAO.

@Database(entities = [ShoppingItem::class], version = 1, exportSchema = false)


abstract class AppDatabase : RoomDatabase() {
abstract fun shoppingItemDao(): ShoppingItemDao
}

Puis, dans une approche avec une Injection de dépendance, il nous reste plus qu’à écrire la definition de notre base de
donnée et notre DAO pour y accéder de partout. Dans l'application, nous utiliserons que le DAO car ce dernier connait
la base de donnée. Nous ne communiquons qu'avec le DAO.

@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {

@Singleton
@Provides
/ge
fun provideDatabase(@ApplicationContext applicationContext: Context): AppDatabase {
return [Link](
applicationContext,
AppDatabase::[Link], "database-name"
).build()
}

@Singleton
@Provides
fun provideCourseDao(appDatabase: AppDatabase): CourseItemDao {
return [Link]()
}
}

🚀 Tout est prêt, vous pouvez utiliser cette nouvelle base de donnée directement ainsi depuis un Repository.
class ShoppingRepository @Inject constructor(
private val shoppingDao: ShoppingItemDao,
) {
fun getAllItems(): Flow<List<ShoppingItem>> = return [Link]()

fun filterItems(filter: String) = [Link](filter)

suspend fun addItem(shoppingItem: ShoppingItem) {

Cours Android 29
[Link](shoppingItem)
}

suspend fun delete(shoppingItem: ShoppingItem) {


[Link](shoppingItem)
}
}

➡ Exemple d'utilisation de Room


Firebase

Remplissez les informations basiques


que vous demande Firebase. Rien de
bien compliqué.

Generer un nouveau projet.

En cours de finalisation...

Cours Android 30
En version écrite :

Add Firebase to your Android project


Install or update Android Studio to its latest version. Make sure that your project meets these
requirements: Targets API level 16 Jelly Bean) or later Uses Gradle 4.1 or later Uses Jetpack
AndroidX, which includes meeting these version requirements: [Link]:gradle v3.2.1
[Link]

En vidéo si vous préférez :

Intégrer Firebase a votre application

[Link]

Base de donnée à distance de Firebase

Installation & Setup on Android | Firebase Realtime Database


If you haven't already, add Firebase to your Android project. Navigate to the Realtime Database section
of the Firebase console. You'll be prompted to select an existing Firebase project. Follow the database
creation workflow. Select a starting mode for your Firebase Security Rules: Test mode Good for getting
[Link]

Dans 🔌 Gradle app, rajouter dans les dependences.


implementation '[Link]:firebase-database'

Pour que ceci fonctionne, il faut auparavant avoir configurer Firebase.


Dans Hilt, on définit notre nouveau module, ici notre base de données se nommant SHOPPING_ITEMS.

@Singleton
@Provides
//generate the reference on the online db
fun provideFirebaseRepository(
ref: DatabaseReference
): ShoppingRepository {
return FirebaseShoppingRepository(ref)
}

@Singleton

Cours Android 31
@Provides
//setup online db
fun provideFirebaseShoppingDatabase(): DatabaseReference {
val databaseName = "SHOPPING_ITEMS"
val database = [Link]()
return [Link](databaseName)
}

Pour retrouver votre base de données sur Firebase, vous devez vous rendre sous l'onglet "Realtime Database" et
activer la fonctionnalité. Indiquez que vous êtes sur un test de développement. Les informations demandées sont
triviales.

La classe suivante nous permet d'ajouter, supprimer, récupérer et filtrer les elements que nous avons sur notre base de
données sur Firebase.

@ExperimentalCoroutinesApi
class FirebaseShoppingRepository @Inject constructor(
private val refOnlineDatabase: DatabaseReference //ref on the online db
) : ShoppingRepository {

override fun getAllItems(): Flow<List<FirebaseShoppingItem>> =callbackFlow{

//create an empty list


val shoppingList: MutableList<FirebaseShoppingItem?> = ArrayList()
[Link](object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
//clear the list if it was used previously
[Link]()

//add item to the list


for (postSnapshot in [Link]) {
val item: FirebaseShoppingItem? = [Link](FirebaseShoppingItem::[Link])
[Link](item)
//send it back over the callback
offer(shoppingList)
}
}

override fun onCancelled(databaseError: DatabaseError) {


Log.e("FirebaseShoppingRepo", [Link])
}
})

//close the flow callback


awaitClose{cancel()}
}

override fun filterItems(filter: String): Flow<List<FirebaseShoppingItem>> =callbackFlow{

//create an empty list


val shoppingList: MutableList<FirebaseShoppingItem?> = ArrayList()

//create a query
val query: Query = [Link]("name").startAt(filter)
.endAt(filter + "\uf8ff"); // "\uf8ff" is actually a Java unicode Escape character
//call your query
[Link](object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
//clear the list if it was used previously
[Link]()
//add item to the list
for (postSnapshot in [Link]) {
val item: FirebaseShoppingItem? = [Link](FirebaseShoppingItem::[Link])
[Link](item)
//send it back over the callback
offer(shoppingList)
}
}

override fun onCancelled(databaseError: DatabaseError) {


Log.e("FirebaseShoppingRepo", [Link])
}
})

//close the flow callback


awaitClose{cancel()}
}

override suspend fun addItem(shoppingItem: ShoppingItem) {


[Link]?.let{[Link](it).setValue(shoppingItem)}

Cours Android 32
}

override suspend fun delete(shoppingItem: ShoppingItem) {


[Link]?.let{[Link](it).removeValue()}
}
}

Il nous reste plus qu'a remplacer LocalShoppingRepository par FirebaseShoppingRepository et vu que ces deux classes
implémentent l'interface ShoppingRepository , nous avons aucun soucis a les échanger.
Il faut voir les interfaces comme un contrat entre l'interface et la classe qui l’étend. Ainsi, vous utilisez ShoppingRepository

sans réellement savoir qui se trouve derriere Local database? Remote database? mais dans tous les cas, on vous
promet des ShoppingItem . 🛍

interface ShoppingRepository {
fun getAllItems(): Flow<List<ShoppingItem>>
fun filterItems(filter: String): Flow<List<ShoppingItem>>
suspend fun addItem(shoppingItem: ShoppingItem)
suspend fun delete(shoppingItem: ShoppingItem)
}

💡 La ligne [Link]?.let{[Link](it).removeValue()}

if([Link]!=null) {[Link]([Link]).removeValue()}
signifie la meme chose que
.
Ici, on utilise la fonction let de Kotlin a la place d'une condition.

Inscription utilisateurs
Pour une utilisation simple et facile, nous utiliserons Firebase, ceci est relativement simple. Cela reprend des concepts
(ajout de Firebase, ajout de dependences) que nous avons deja vu.

De plus, la documentation est en Français pour une fois. La majorité de la documentation de Firebase l'est. Tel de futur
dev, je vous laisse lire la documentation parce que RTMF.

Pour gérer une inscription utilisateur facilement :

Easily add sign-in to your Android app with FirebaseUI


FirebaseUI is a library built on top of the Firebase Authentication SDK that provides drop-in UI flows
for use in your app. FirebaseUI provides the following benefits: Multiple Providers - sign-in flows for
email/password, email link, phone authentication, Google Sign-In, Facebook Login, Twitter Login, and
[Link]

App Publishing
Play Store

Android App Distribution Tutorial: From Zero to Google Play Store


From Zero to Google Play Store: Learn how to get your completed Android app on the Google Play
Store in this step-by-step Android app distribution tutorial. Version Kotlin 1.3, Android 10.0, Android
Studio 3.5 Update note: Pablo Sanchez Egido updated this tutorial for Kotlin 1.3, Android 10 and
[Link]
play-store

Machine Learning
ML Kit

Cours Android 33
ML Kit | Google Developers
Machine learning for mobile developers

[Link]

Firebase Machine Learning


Use machine learning in your apps to solve real-world problems. Firebase Machine Learning is a mobile SDK that brings Google's machine learning
expertise to Android and iOS apps in a powerful yet easy-to-use package. Whether you're new or experienced in machine learning, you can implement
the functionality you need in just a few lines of code.
[Link]

Autre
Afficher des images venant d'ailleurs
Dans 🔌 Gradle app, rajouter les dependences pour Glide.
//Glide
implementation '[Link]:glide:4.11.0'
annotationProcessor '[Link]:compiler:4.11.0'

Rajouter une classe avec simplement cette ligne

@GlideModule
class GlideApp : AppGlideModule() {
}

Rajouter une extension, dans un fichier a part. Un exemple est disponible dans le projet sur les RecyclerViews. Une
extension est, tout simplement, le fait de rajouter une fonction a une classe qui ne nous appartient pas, ici ImageView,
qui vient d'Android pure.

fun [Link](url: String) {


[Link](context) //the context for the imageview calling it
.load(url) // the url of the image to display
.into(this) // this refer to the imageview where to put the loaded file
}

Rajouter dans le [Link]

<uses-permission android:name="[Link]" />

Il ne nous reste plus qu’à appeler cette nouvelle méthode où nous en avons besoin.

val imgUserProfile : ImageView = [Link]([Link].img_profile)


[Link](userPicture) //must be a web link to a image

Faire un click

val tvName: TextView = [Link]([Link].tv_name)


[Link] { /*Do whatever you want, call another method for example*/ }

Recuperer le texte d'un champ

Cours Android 34
val etQuantity: EditText = [Link]([Link].et_quantity)
[Link] { doMagic([Link]())}

fun doMagic(quantityText : String){


//...do whatever you want
}

Resource
Ray Wenderlich
Meilleur ressource pour apprendre le développement mobile, aussi bien iOS, Android que Flutter. La partie gratuite du
site est une mine d'or.

[Link] | High quality programming tutorials: iOS, Android, Swift, Kotlin, Flutter, Server Side Swift, Unity, and more!
Learn iOS and Swift, Android and Kotlin & Dart and Flutter development with the largest and highest-quality catalog of video courses and
books on the Internet. A [Link] Subscription gives you access to: 4,000 mobile development videos 50 development books
Curated learning paths Access to our iOS and Android app and more...
[Link]

Google Codelabs
Les tutos de Google, dans de nombre categories. Ici, Android.

Google Codelabs
Google Developers Codelabs provide a guided, tutorial, hands-on coding experience. Most codelabs will step you through the process of building a small
application, or adding a new feature to an existing application. They cover a wide range of topics such as Android Wear, Google Compute Engine, Project
Tango, and Google APIs on iOS.
[Link]

Android Guide
Demonstration pas a pas de comment intégrer telle ou telle fonctionnalités. Vous retrouverez un grand nombre de sujet
abordés dans le menu de gauche (permission, camera, notif, etc...)

[Link]

Youtube
Si jamais, vous avez besoin de tutoriel plus pas a pas, la communauté Android est assez active sur Youtube. Voici une
selection que quelques bons développeurs.
Android

Android Developers
Welcome to the official Android Developers YouTube channel. Get the latest Android news, best
practices, live videos, demonstrations, tutorials, and more! Subscribe to receive the latest on Android
development → [Link]
[Link]

Coding with Mitch

[Link]

Coding with Flow

Cours Android 35
Coding in Flow
Hey guys, my name is Florian Walther and I create focused, concise, and clear programming tutorials.
All my videos can also be found at [Link] where they are ordered into different
categories. If you want to connect with other developers, make sure to visit our Discord chat.
[Link]

Pour le reste, Google est votre ami, ainsi que Medium ou [Link]. Et aussi StackOverflow 😉

Cours Android 36

Vous aimerez peut-être aussi