Gran reapertura de la tienda: cargando datos en Android usando corutina

Les traigo a su atención una traducción del artículo original de Mike Nakhimovich


Érase una vez, trabajé en el New York Times y creé una biblioteca llamada Store, que era "la biblioteca de Java para la carga de datos fácil y receptiva". Creamos la tienda usando RxJavaplantillas tomadas de la implementación de la caché de guayaba . Los usuarios de la aplicación de hoy esperan que las actualizaciones de datos se realicen en la interfaz de usuario sin tener que hacer cosas como tirar para actualizarpara actualizar datos o moverse entre pantallas de un lado a otro. La interfaz reactiva me hizo pensar en cómo podemos tener almacenes de datos declarativos con API simples que abstraigan funciones complejas como la aceleración multitarea y el almacenamiento en caché de disco, que son necesarios en las aplicaciones móviles modernas. En sus tres años de operación, Store tiene 45 contribuyentes y más de 3,500 estrellas de GitHub. A partir de ahora, me complace anunciar que Dropbox se encargará del desarrollo activo de la Tienda y lo lanzará completamente en Kotlin con soporte para Coroutinesy Flow. Y ahora Store 4, esta es una oportunidad para aprovechar lo que hemos aprendido al repensar la API y las necesidades actuales del ecosistema de Android.




Android . . , , Google. , Android. Android Jetpack:



, Android Jetpack :



https://developer.android.com/jetpack/docs/guide


  • :  , AndroidX , Lifecycle Scopes . , view- .
  • View Model Live Data:  , , ( , !).
  • Room:  SQLite, ORM RxJava .
  • Remote Data Source:  Jetpack, Retrofit Okhttp Square .

, , , ( , , Jetpack ;-) ). , . , Dropbox Store, , .


, Store, . ,


«… , , .  , , , ».

. , , , . , .


Store?


, , Store, Android- . — , . , UX. , , . , . Store, .


, , . …



Store :



Store


, , Store, , , .


4 – Android . , . , Room SQLDelight, , . -, push-, Firebase, «» . Store , , , , , . , Store: http://github.com/dropbox/Store.


Store 4 . RxJava , Flow.


, , , , RxJava? . , , . , . , , , , .


— . RxJava - . API RxJava :


// Observable.java
@CheckReturnValue
public final Disposable subscribe(Consumer onNext) {}

, , RxJava Observable Disposable . dispose(), . . RxJava2 @CheckReturnValue— , flowable.subscribe , . , , . , RxJava, .


RxJava , dispose(). . RxJava, , , Kotlin Flow , . , Flow . Flow , .


suspend fun Flow.collect(...)

Collect RxJava, , Flow. RxJava, collect() "suspend". , ( async/await), . Flow.collect , , .


, Android ( ) , , . , Kotlin, , viewModelScope Jetpack, , . , Android: , .


public fun CoroutineScope.launch(...)
 
viewModelScope.launch {
  flow.collect{ handle(it) }
}

, Flow. Android. , AndroidX . , ViewModel, , Room Flow. , (Paging). Store , Android , .


, Store , Android, , , , Kotlin multi-platform, . RxJava Kotlin native/js 6000 .


Store?


Store . Store, Fetcher, , , . , Store . Store Flow, — ! Store // , , .


Store


, Store. , :


StoreBuilder.fromNonFlow { api.fetchSubreddit(it, "10")}
            .persister(
              reader = db.postDao()::loadPosts,
              writer = db.postDao()::insertPosts,
              delete = db.postDao()::clearFeed)
            .cachePolicy(MemoryPolicy)
            .build()

:


  • ,
  • API , , .

Store  . persister() Store. , Observable, Jetpack Room, SQLDelight Realm.


:


Store



 Store  . , Flow, , ReturnType.


val store = StoreBuilder.from {
                articleId -> api.getArticle(articleId) //Flow<Article>
            }
            .build()

Store , , toString(), equals() hashCode(). Fetcher . . , equals() hashcode() data- Kotlin.


: Stream



API, Store, :


fun stream(request: StoreRequest<Key>):Flow<StoreResponse>Output>>

StoreRequest, , . StoreResponse. StoreResponse — Kotlin, Loading, Data Error. StoreResponse ResponseOrigin, , .



  • Loading ResponseOrigin. .
  • Data , , Store.
  • Error , , ResponseOrigin.

Store , StoreResponse.Error, Flow , , . - , render/updateUI . . :


lifecycleScope.launchWhenStarted {
  store.stream(StoreRequest.cached(key = key, refresh=true)).collect { response ->
    when(response) {
        is StoreResponse.Loading -> showLoadingSpinner()
        is StoreResponse.Data -> {
            if (response.origin == ResponseOrigin.Fetcher) hideLoadingSpinner()
            updateUI(response.value)
        }
        is StoreResponse.Error -> {
            if (response.origin == ResponseOrigin.Fetcher) hideLoadingSpinner()
            showError(response.error)
        }
    }
  }
}

: Store.get(key)Store.stream(key)  Store.fresh(key).


  • suspend fun Store.get(key: Key): Value
 — . , .
  • suspend fun Store.fresh(key: Key): Value
 — , .
  • suspend fun Store.stream(key: Key): Flow
 — (Flow) .

get():


lifecycleScope.launchWhenStarted {
  val article = store.get(key)
  updateUI(article)
}

store.get(key), ( ), . store.get(key) , . ( ) , . , , , Store. Store . Store , , .



 store.fresh(key)  ( ). ,  fresh()  ,  store.get()/stream()  .  fresh()  pull-to-refresh .
 fresh()  get()  .


Stream



, store.stream(key), , , / . stream() , .


lifecycleScope.launchWhenStarted { 
  store.stream(StoreRequest.cached(3, refresh = false)) 
.collect{ }
 
 
store.stream(StoreRequest.get(3)) // ,   
    .collect{  }




, Store . , , , . , . Store.get() 12 . , . .




 Store ,  persister()  . , , Store , , .



persister(),  Flow  Store  . , ,  Store,   Store.


, Observable (Jetpack Room, SQLDelight Realm), , , UX.


StoreBuilder.fromNonFlow {api.fetchSubreddit(it, "10")}
            .persister(
              reader = db.postDao()::loadPosts,
              writer = db.postDao()::insertPosts,
              delete = db.postDao()::clearFeed)
            .cachePolicy(MemoryPolicy)
            .build()

Store , . , Store (Realm, SQLite, Firebase ..). SQLite Room, Jetpack.


API Store — , . :


  • , Room
  • (StoreRequest)
  • (stream)
  • API, Kotlin.


, Store. , , Android, . , -, - . , , .


KotlinConf:





Store : github.com/dropbox/Store




, , Android Open Source Project, , Creative Commons 2.5 Attribution License


All Articles