Formatowanie danych z LiveData

0

Hej,

Po wejściu do fragmentu, pobieram dane o produkcie z Firestora. Przekazuje dane o produkcie do widoku poprzez dataBinding i mam problem
Próbuje zrozumieć jak powinno się to dobrze i efektywnie robić.

Produkt składa się między innymi z ceny, w Firestorze zapisywanej jako Long, np 700. Przed wyświetleniem potrzebuje cene sformatowac, np do postaci £700.00.
Oczywiście w momencie inicjalizowania viewModelu dane nie są jeszcze zwrócone więc formater nie może zadziałać.
Nakierujcie proszę na rozwiązanie:

class ProductDetailViewModel(private val productUid: String) : ViewModel() {

    private val auth = Firebase.auth
    private val repository = FirebaseCloud()
    private val currentUser = repository.getCurrentUser()

    val currentProduct: LiveData<Product>
        get() = repository.currentProduct

    private fun getSingleProduct() {
        repository.getSingleProduct(productUid)
    }

    init {
        getSingleProduct()
    }
}

2

Ok rozwiazanie to:

  1. napisz oddzielną klasą do formatowania z metodą ~ format(value: Long) : String
  2. wstrzyknij to do viewmodelu
  3. val currentProduct: LiveData<Product>
    get() = repository.currentProduct pewnie da się przerobić na ~
    val currentProduct: LiveData<ProductViewEntity>
    get() = repository.currentProduct.map( ProductView(theMapper.format(it.price)) )

a) pobierasz dane
b) formatujesz potrzebne dane
c) pakujesz to w ___ViewEntity - tutaj powinny być przygotowane dane do wyświetlenia na widoku + viewbinding spięty - to jest model z viewbindingu

Bonusowe pytanie:
Cena w Longu?! BigDecimal for the rescue. Jeśli to jest coś więcej niż projekt ~hell world dla androida to zagadaj z leadem projektu żeby zmienić kontrakt.

0

Kurcze

@lubie_programowac: No rozwiązałeś problem :D Dziękuje! Działa, tak jak trzeba ale pojawił się kolejny problem bo mimo iż NIBY rozumiem co dokładnie się dzieje i w moment to napisałem to troszke to jest taki hm God Send, mógłbyś objaśnić dlaczego używając map mam wystawiony dokładnie taki produkt jak chciałem?

Skleciłem tak i od tego wyjde bo działa chyba że to jest dokładnie tak jakbyś to widział

val currentProduct: LiveData<ProductEntity>
        get() = repository.currentProduct.map {
            ProductEntity(
                it.uid,
                it.name,
                it.brand,
                Utils.formatPrice.format(it.price))
        }

napisz oddzielną klasą do formatowania z metodą ~ format(value: Long) : String
wstrzyknij to do viewmodelu

Tak, to już miałem

Bonusowe pytanie:
Cena w Longu?! BigDecimal for the rescue. Jeśli to jest coś więcej niż projekt ~hell world dla androida to zagadaj z leadem projektu żeby zmienić kontrakt.

Hehehe oczywiście bardzo mi pochlebiasz i zapamiętam na przyszłość ale mobilnym developerem dopiero będe :D

A co do powodów to mniej więcej: https://stackoverflow.com/questions/51373408/how-to-store-bigdecimal-in-firestore-in-android
Doczytam o BigDecimal

1

Tutaj jest kilka spraw do analizy / poprawy młody padawanie.

W poprzednim wpisie napisałem że moje rozwiązanie jest ok a nie idealne. Możemy wspólnie pociągnąć temat i zrobić z tego dobrą architekturę + testy. Odpowiem na Twoje pytanie ale dopiero po dwóch / trzech innych krokach które pomogą ukształtować dobrą architekturę.

Zanim wskoczymy do tematu ~God Send sugeruję
a) dodanie daggera / Hilta / koina / innego dependency injection do projektu - osobiście Hilt wygląda spoko, tutaj masz laby do niego: https://developer.android.com/codelabs/android-hilt#0
b) zamienienie Utils.formatPrice.format na klasę ~PriceFormatter(locale: Locale (?) ) z metodą format i dodanie jej do viewmodelu przez konstruktor a nie jako UtilsSingletonFactoryManager.
c) dodanie testów do PriceFormattera + tego viewmodelu.

Jak to będzie hulać można przejść dalej.

Jak już będziesz siwy albo będziesz wyrywać włosy przy próbie dodawania DI do projektu możesz otworzyć kolejny temat na forum bo to będzie inny wątek.

Powodzenia!

//Edit: Odpowiadając połowicznie na Twoje pytanie: https://www.freecodecamp.org/news/a-quick-introduction-to-clean-architecture-990c014448d2/ clean architecture. Klasa ~mapujący czyli Entity oddziela UI and warstwy prezentacji. Ogólnie to jest spoko pomysł - ja natomiast stosuję metodę bardziej pod MVVM i nie przerzucam entity a states ale jak już mówiłem opowiem o tym później.

0

Ile ja się na głowił żeby wstrzyknąć konstruktor przekazywany do viewModelu przez safeArgs! :D Ale działa dobrze i zgodnie z dokumentacją, teraz pewnie będzie jeszcze trudniej, mam nadzieje @lubie_programowac w weekend podesłać gita to jak będziesz miał czas to zerkniesz jak to wygląda. Dziękuje!

0

Coś tam się kształtuje:

  • ProductEntityMapper - Dodałem interfejs mapujący response na produkt gotowy do wyświetlenia, wystawiany na gotowo z repo do viewModelu
  • FirebaseInterface oraz FirebaseDatabaseModule - Do wstrzykiwania firestora i abstrakcji wszystkich metod uzywanych w repo do pobierania danych
  • FirebaseAuthModule - Do wstrzykiwania autha, plus od nowa metody i wstrzykniete zaleznosci do obslugi logowania, rejestracji i updatu UI, tez z uzyciem swojego mappera
  • Po tych zmianach plus poprawa SoC zmniejszyła mi fragmenty ze 100-120 linijek na około 45 heh

Generalnie bardzo się jaram, sama poprawa architektury rozwiązała kilka problemów.

Muszę jednak użyć troche profilera bo wydaje mi sie, że apka działa wolniej ale moze to emulator bo ram i swap juz pod korek. Tu nasuwa sie pytanie, czy używając firebase jako zrodla danych powinienem uzywac modułów hilta na scopie SingletonComponent czy Activity będzie lepszym wyborem?

0

Zanim wskoczymy do spraw wydajnościowych: testy są? Przynajmniej: ViewModel + UI Espresso / Barista / appium + testy mapperow + testy repozytorów dla jednego ekranu. SonarQube / SonarCloud dobrze pokazuje pokrycie testami, możesz dodać do środowiska.

Przed poprawieniem wydajności tak jak napisałeś, warto dodać profilera. Machnij to, opowiedz jak to zrobiłeś, pokaż aktualną wydajność (jak zrobisz UI tests to będziesz pewnie mógł te same testy wykorzystać do analizy wydajności apki).

1 użytkowników online, w tym zalogowanych: 0, gości: 1