web-dev-qa-db-fra.com

Rxjava synchrone ou asynchrone dans le Worker (à partir du composant WorkManager), quel est le bon choix?

Je suis nouveau dans le nouveau composant d'architecture WorkManager, je fais mes appels d'API via Retrofit et RxJava.

Mon cas d’utilisation ici est d’obtenir de nouvelles publications du Backend, puis d’afficher une notification et de mettre à jour un widget.

Ainsi, le code de la méthode doWork () de la classe Worker peut ressembler à quelque chose comme ceci.

@NonNull
  @Override
  public Result doWork() {
    AppDependencies appDependencies = new AppDependencies((Application) getApplicationContext());
    Repository repository = appDependencies.getRepository();

    repository.getNewPosts()
        .flatMap(newPosts -> repository.inserPosts(newPosts).toObservable())
        .doOnError(Timber::e)
        //if success - > return  Result.SUCCESS,
        // -> show notification
        // -> update widget
        // error-> return Result.Failure
        .dontKnowWhatBestNextThing; //blocking or subscribing

    //if we reached here then Retry
    return Result.RETRY;
  }

Ma question est de savoir quelle est la bonne façon d'utiliser un code RxJava dans la classe Worker car la méthode doWork () a une valeur de retour, dois-je donc rendre le code Rx synchrone.

si j'utilise l'approche Rx non bloquante, comment puis-je retourner de la valeur (Succès - Échec - Réessayer) 

10
Mohamed Ibrahim

Depuis la version 1.0.0-alpha12 de WorkManager, ils ont ajouté un nouvel artefact appelé work-rxjava2 qui inclut RxWorker class exactement à cette fin. C'est un cas particulier de ListenableWorker en attente de Single<Result>

Pour l'implémenter, assurez-vous d'abord d'inclure les artefacts corrects dans votre build.gradle:

dependencies {
   ...
   implementation "Android.Arch.work:work-runtime-ktx:1.0.0-beta01"
   implementation "Android.Arch.work:work-rxjava2:1.0.0-beta01"
}

Et implémentez votre RxWorker:

class MyRxWorker(context : Context, params : WorkerParameters) : RxWorker(context, params) {

    val remoteService = RemoteService()

    override fun createWork(): Single<Result> {
        return remoteService.getMySingleResponse()
                .doOnSuccess { /* process result somehow */ }
                .map { Result.success() }
                .onErrorReturn { Result.failure() }
    }
}
13
Semanticer

Edition: WorkManager prend désormais officiellement en charge une RxWorker. Jetez un oeil à la réponse ci-dessus pour plus d'informations. 

doWork se produit sur un thread d'arrière-plan. Donc, il est sécuritaire de bloquer. Vous devez attendre la fin de la Observable avant de renvoyer une Result

Nous travaillons également à rendre cela plus facile avec les API asynchrones. Restez à l'écoute.

5
Rahul

J'ai trouvé la solution. Vous devez utiliser RxWorker ou SettableFuture pour un travail asynchrone

Ceci est ma solution pour obtenir l'emplacement actuel. Travailler comme un charme

class LocationWorker(context: Context, private val workerParams: WorkerParameters) :
ListenableWorker(context, workerParams) {

lateinit var mFuture: SettableFuture<ListenableWorker.Result>
private var fusedLocationProviderClient = FusedLocationProviderClient(context)

@SuppressLint("RestrictedApi", "MissingPermission")
override fun startWork(): ListenableFuture<Result> {
    val uniqueId = workerParams.inputData.getString(UNIQUE_ID_KEY)
    mFuture = SettableFuture.create()
    Timber.d("mFutureStart")
    fusedLocationProviderClient.lastLocation.addOnSuccessListener { location ->
        Timber.d("location == $location")
        if (location != null) {
            mFuture.set(Result.success())
        } else mFuture.set(Result.failure())
      }
    return mFuture
   }
}
0
Edgar Khimich

Oui, rendre le code Rx synchrone. La documentation de doWork est minimale, mais l’utilisation du mot «arrière-plan» implique qu’il est attendu ou au moins autorisé à bloquer. Et bien sûr, vous ne pouvez pas savoir ce que doWork doit renvoyer avant que la requête réseau ait été résolue.

0
TKK