1 of 36

Tehnici avansate pentru

dezvoltarea aplicațiilor mobile

11 - Compose - Repository și injectarea dependențelor

2 of 36

Separarea layer-elor

2

3 of 36

Recapitulare

  • În prezentarea trecută:
    • din ViewModel am obținut date de la un serviciu web folosind un service API
    • simplu de implementat
    • nu scalează la mai multe surse de date

11 - Compose - Repository și injectarea dependențelor

3

4 of 36

Separea layerelor

  • Recomandare: separarea layerelor UI și date
    • scalabilitate, robustețe, ușurința testării
    • colaborare între dezvoltatori

  • Arhitectura Android:
    • cel puțin 2 layere: UI și Data

11 - Compose - Repository și injectarea dependențelor

4

5 of 36

Data Layer

  • Include logica aplicației

  • Obținerea și salvarea datelor

  • Expune datele către layerul UI
    • prin modelul fluxului de date unidirecțional

11 - Compose - Repository și injectarea dependențelor

5

6 of 36

Data Layer

  • Surse de date:
    • rețea (serviciu web)
    • bază de date locală
    • fișiere de pe dispozitiv

11 - Compose - Repository și injectarea dependențelor

6

7 of 36

Separarea layerelor

  • Separarea preocupărilor (separation of concerns)
    • Modificarea unei părți a codului nu va afecta alte părți

  • Layerul de UI doar va afișa datele
    • Nu se preocupa cu obținerea lor
  • Layerul de date este responsabil cu obținerea datelor

11 - Compose - Repository și injectarea dependențelor

7

8 of 36

Arhitectura aplicațiilor

11 - Compose - Repository și injectarea dependențelor

8

9 of 36

Layerul de date

  • Include unul sau mai multe repo-uri

  • Fiecare repo poate conține
    • zero sau mai multe surse de date

  • Recomandare:
    • câte un repo pentru fiecare tip de sursă de date

11 - Compose - Repository și injectarea dependențelor

9

10 of 36

Clasa Repository

  • Expune datele către restul aplicației
  • Centralizează modificările asupra datelor
  • Rezolvă conflicte între mai multe surse de date
  • Abstractizează sursele de date față de restul aplicației
  • Include logica aplicației

11 - Compose - Repository și injectarea dependențelor

10

11 of 36

Repository - interfață - exemplu

  • În pachetul data

  • O interfață
    • nume = tip de date + “Repository”
  • Funcție suspendabilă - apelată din corutină

11 - Compose - Repository și injectarea dependențelor

11

12 of 36

Repository - clasă - exemplu

  • Clasă care implementează interfața repo
  • Override la funcția suspendabilă
    • obține o listă de obiecte de la serviciul Retrofit API

12

13 of 36

Repository - ViewModel - exemplu

  • În ViewModel
    • instanțiată clasa repo și folosită funcția getMarsPhotos()

11 - Compose - Repository și injectarea dependențelor

13

14 of 36

Separarea layerelor

  • ViewModel nu mai face cererea de rețea
    • nu mai folosește direct MarsApi
  • Acum ViewModel folosește repo-ul
    • repo-ul folosește MarsApi pentru a face cererea de rețea

11 - Compose - Repository și injectarea dependențelor

14

15 of 36

Injectarea dependențelor

15

16 of 36

Dependențe

  • O clasă are nevoie de obiecte ale altor clase = dependențe

  • 2 modalități de a furniza obiectele:
    • 1. clasa instanțiază singură obiectele
    • 2. le primește ca argumente prin constructor

= injectarea dependențelor

11 - Compose - Repository și injectarea dependențelor

16

17 of 36

Dependențe - exemplu

1. clasa instanțiază singură obiectele

  • cod inflexibil, greu de testat
  • clase strâns cuplate

11 - Compose - Repository și injectarea dependențelor

17

18 of 36

Dependențe - exemplu

2. clasa primește obiectele ca argumente prin constructor

  • injectarea dependețelor
  • cod flexibil, ușor de testat, ușor de extins
  • clase slab cuplate

11 - Compose - Repository și injectarea dependențelor

18

19 of 36

Injectarea dependențelor (DI)

  • Pasarea obiectelor la runtime
    • În loc sa fie hardcodate în clasa care le folosește

  • Inversiune a controlului

11 - Compose - Repository și injectarea dependențelor

19

20 of 36

Injectarea dependențelor (DI)

  • Avantaje:
    • reutilizarea codului
      • nu depinde de un anumit obiect
    • refactorizarea codului
      • slab cuplat
    • facilitează testarea
      • obiecte de test

11 - Compose - Repository și injectarea dependențelor

20

21 of 36

Facilitarea testării

  • DI facilitează testarea
    • se efectuează apelul către rețea
      • sunt primite datele corect
    • obiect de test care simulează apel de rețea
      • returnează date fictive

11 - Compose - Repository și injectarea dependențelor

21

22 of 36

Facilitarea testării

  • ViewModel mai ușor de testat
    • eliminăm dependența de repository
    • să nu mai creeze repository-ul
    • ci să primească obiectul repository
    • => folosim injectarea dependențelor

11 - Compose - Repository și injectarea dependențelor

22

23 of 36

Container

  • Folosirea unui container al aplicației
    • o clasă ce conține obiectele importante ale aplicației
    • conține dependențele aplicației
    • un loc comun pentru obiecte, acces mai ușor

  • Containerul poate include un repository
    • ViewModel primește repository de la container

11 - Compose - Repository și injectarea dependențelor

23

24 of 36

Container - exemplu

11 - Compose - Repository și injectarea dependențelor

24

25 of 36

Container - exemplu

  • Containerul conține toate dependențele aplicației
    • URL-ul de bază
    • obiectul Retrofit
    • serviciul API Retrofit
    • obiectul repository

25

26 of 36

Repository - exemplu

  • Repo-ul primește ca parametru serviciul API Retrofit
  • Containerul instanțiază repo-ul și îi dă serviciul ca argument
  • Exemplu de injectare a dependenței

11 - Compose - Repository și injectarea dependențelor

26

27 of 36

Container

  • Avantaje:
    • gestionare mai bună a dependențelor
    • facilitează injectarea dependențelor în alte clase
      • ex: ViewModel
    • facilitează testarea și refactorizarea

27

28 of 36

Cum atașăm containerul la aplicație?

11 - Compose - Repository și injectarea dependențelor

28

29 of 36

Cum atașăm containerul la aplicație?

11 - Compose - Repository și injectarea dependențelor

29

30 of 36

Injectarea dependenței în ViewModel

  • ViewModel are constructor cu parametru privat = repo-ul
    • primit de la containerul aplicației
    • injectarea dependenței

11 - Compose - Repository și injectarea dependențelor

30

31 of 36

Injectarea dependenței în ViewModel

  • Framework-ul Android NU permite ca ViewModel să primească valori în constructor
    • => vom folosi un obiect ViewModelProvider.Factory

31

32 of 36

Injectarea dependenței în ViewModel

  • Obiect companion în cadrul clasei ViewModel
  • Obiectul factory
    • obține o referință la obiectul repo din container
    • crează un obiect ViewModel cu repo-ul ca argument

11 - Compose - Repository și injectarea dependențelor

32

33 of 36

Creare ViewModel folosind factory

  • viewModel() = o funcție de bibliotecă
    • crează un obiect ViewModel printr-o anumită metodă
    • îi dăm factory-ul și îl folosește pentru a returna un obiect

11 - Compose - Repository și injectarea dependențelor

33

34 of 36

Îmbunătățiri

  • Refactorizarea aplicației:
    • Folosire repository
    • Injectarea dependențelor

  • Folosire repo => separarea layerului de UI și date

  • Injectarea dependențelor
    • => testare mai ușoară pentru ViewModel

11 - Compose - Repository și injectarea dependențelor

34

35 of 36

Bibliografie

11 - Compose - Repository și injectarea dependențelor

35

36 of 36

Cuvinte cheie

  • Separarea layerelor
  • Layerul de date
  • Repository
  • Dependențe
  • Injectarea dependențelor
  • Container
  • ViewModel
  • Factory

11 - Compose - Repository și injectarea dependențelor

36

36