2014-09-15 1 views
2

J'utilise RxJava pour déplacer l'accès réseau à un thread distinct dans Android, mais mon interface utilisateur est toujours bloquée.Le blocage de l'interface utilisateur se produit dans Android malgré RxJava

Je ne suis pas en utilisant le mauvais observable comme indiqué ici: Android RxJava, Non Blocking?

Les codepoints [A], [B] et [C] dans le code ci-dessous sont passés dans l'ordre [A] -> [C] - > [B] donc le thread courant est traité correctement et RxJava appelle [C] dès qu'il a un résultat. C'est bon.

En outre, le blocage est beaucoup mieux que de faire l'appel réseau sur le thread UI, mais j'ai encore un blocage mineur. L'interface utilisateur reste fluide après l'appel, mais si le serveur ne répond pas en quelques millisecondes, il bloque.

private search; // search is an instance variable in the same class 

    // [A] 

    Observable.just(search.find("something")) // search.find calls the REST endpoint 
      .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) 
      .subscribe(new Action1<Search>() { 

       @Override public void call(Search search) { 
        // further processing // [B] 
       } 

      }, new Action1<Throwable>() { 

       @Override public void call(Throwable throwable) { 
        // error handler 
       } 

      }); 

    // [C] 

Serait-ce un problème que la recherche est une variable d'instance dans la même classe où le Observable utilise, mais l'appel de point final est effectué à partir d'une bibliothèque séparée? Cela ne devrait pas avoir d'importance, n'est-ce pas? Est-ce que je fais quelque chose de mal que je ne devrais pas faire?

-

Trouver ressemble à ceci (supprimé la gestion des exceptions par souci de concision):

public Search find(String searchtext) { 
    setSearchtext(searchtext); 
    SearchEndpoint.find(Session.getUser().getId(), searchtext); 
    return this; 
} 

SearchEndpoint comme ceci:

public static Search find(final Long userId, final String searchtext) throws IOException { 
    return ApiService.api().searches().find(userId).setFind(searchtext).execute(); 
} 

et fait un appel à l'extrémité de nuage Google généré bibliothèque.

+0

Pourriez-vous poster plus d'informations sur votre méthode search.find? Je suppose que son type de retour est Search et c'est un simple appel de méthode synchrone? Dans ce cas, just() appelle search.find(), bloque jusqu'à ce qu'il renvoie une valeur et encapsule ensuite cette valeur dans un observable, qui appellera instantanément OnNext puis onCompleted. Au lieu de cela: utilisez RetroFit, ou jetez un oeil à Observable.create pour envelopper correctement votre appel REST dans un Observable ...Demandez à nouveau, si vous avez besoin de plus d'aide! –

Répondre

3

Essayez ceci:

Observable.create(new Observable.OnSubscribe<Search>() { 

    @Override 
    // method signature is from memory - I hope I am correct... 
    public void call(Subscriber<? super Search> subscriber) { 
     try { 
      Search search = search.find("something"); 
      subscriber.onNext(search); 
      subscriber.onCompleted(); 
     } catch (SomeException e) { 
      subscriber.onError(e); 
     } 
    } 
}) 
// and then continue with your .subscribeOn(...) 

Pour clarifier les choses, peut-être ce qui rend le problème avec votre code plus évident:

Observable.just(search.find("something")) 

est clairement équivalent à

Search search = search.find("something"); 
Observable.just(search) 

Et cela rend évident que search.find est exécuté avant que nous passions le contrôle à rxjava et il est exécuté sur tout thread vous êtes actuellement sur - puis la construction d'un Observable de la valeur pré-calculée et la livraison de la valeur se produire sur un autre thread, mais cela ne vous aide pas beaucoup ...

+0

J'ai commencé à utiliser RxJava hier et je pensais que RxJava exécuterait tout ce qui est derrière (juste) l'utilisation de la réflexion. Si ce n'est pas le cas, alors votre explication prend tout son sens. C'est marrant mais ça m'a aidé un peu. [Je ne peux pas tester maintenant, mais je le ferai plus tard et je vous donnerai des commentaires.] –

+0

Y a-t-il une raison pour laquelle vous redéfinissez la recherche de variables? Recherche search = search.find ("quelque chose"); -> L'EDI me dit "(la recherche) n'a peut-être pas été définie". Si je vais search = search.find ("quelque chose"); le code compile bien. –

1

Je sais que c'est quelques mois - mais au lieu de create ing une toute nouvelle observable (ce qui est relativement sujette aux erreurs), vous pouvez utiliser l'opérateur map pour lancer la recherche:

String search_input = "something"; // this is where you can specify other search terms 
Observable.just(search_input) 
     .map(s -> search.find(s)) // search.find calls the REST endpoint 
     .subscribeOn(Schedulers.io()) 
     .observeOn(AndroidSchedulers.mainThread()) 
     .subscribe(// your subscriber goes here 

Si vous n'utilisez lambdas, que map fonction devrait ressembler à:

.map(new Func1<String, Search>() { 
     @Override   
     public Search call(String s) { 
      return search.find(s) 
     } 
}) 
Questions connexes