Cours Android: Jeremie Guillot
Cours Android: Jeremie Guillot
Cours Android
Jeremie Guillot
Support de cours produit par Jérémie Guillot, développeur Android freelance.
📨 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.
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
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
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
5. Enveloppe budgétaire
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
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.
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.
Debug
Cours Android 5
Attach Debut :
Gradle :
[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.
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...
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)
// accessing values
// indexed iteration
[Link] { index, value ->
println("Value at index $index is $value")
}
// 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]()}")
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
Mutability
fun main() {
val mutableItems = mutableListOf<Worker>()
items = listOf("Fourth")
println(items)
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 :
Pour définir une variable annulable, nous devons ajouter un point d'interrogation ( ? à la déclaration de type :
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.
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 :
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 :
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)
fun main() {
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.
Néanmoins, les bases présentés ici suffissent pour suivre le cours sur Android.
Cours Android 10
Android Developpment
User Interface
LinearLayouts
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
Source
Avec app:layout_constraintVertical_chainStyle="packed" , on peut gerer la distribution de plusieurs vues enchainer les unes au
autres:
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
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
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
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.
/**
* 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])
}
return ViewHolder(view)
}
// Get element from your dataset at this position and replace the
// contents of the view with that element
[Link] = dataSet[position]
}
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/element_text"/>
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.
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"
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
Source
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.
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
// 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
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).
Il faut rajouter cette ligne dans le fichier [Link] Module : .app ) > dependencies .
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 :
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?
)
class EventsRepository(
private val apiClient: ApiClient
) {
suspend fun getHistoricalEvents() = [Link]()
}
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.
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 :
packagingOptions {
exclude("META-INF/*.kotlin_module")
}
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() {
}
<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])
}
}
@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 .
@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 .
[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 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.
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.
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]()
Cours Android 29
[Link](shoppingItem)
}
En cours de finalisation...
Cours Android 30
En version écrite :
[Link]
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 {
//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)
}
}
Cours Android 32
}
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.
App Publishing
Play Store
Machine Learning
ML Kit
Cours Android 33
ML Kit | Google Developers
Machine learning for mobile developers
[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'
@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.
Il ne nous reste plus qu’à appeler cette nouvelle méthode où nous en avons besoin.
Faire un click
Cours Android 34
val etQuantity: EditText = [Link]([Link].et_quantity)
[Link] { doMagic([Link]())}
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]
[Link]
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