2016-06-26 13 views
3

Nach diesem tutorial habe ich zwei Quellen zum Abrufen von Daten erstellt. Ich erwarte, dass, wenn es keine Daten lokal gibt, ich Netzwerkanfrage senden werde. Aber die ganze Zeit erhalten Sie eine Liste von Null-Objekten von der lokalen Quelle (die zuerst in Observable.concat ist).RxAndroid: Observable.first() gibt die Liste der Null-Objekte zurück

Für die lokale Quelle SQLite mit SQLBrite Wrapper und für Remote-Quelle Retrofit:

@Override 
public Observable<Item> get(String id) { 
    //creating sql query 

    return databaseHelper.createQuery(ItemEntry.TABLE_NAME, sqlQuery, id) 
     .mapToOneOrDefault(mapperFunction, null); 
} 

Es gibt Methode in Repository für concating Observablen:

@Override 
public Observable<Item> get(String id) { 
    Observable<Item> local = localDataSource 
     .get(id) 
     .doOnNext(new Action1<Item>() { 
      @Override 
      public void call(final Item item) { 
       // put item to cache 
      } 
     }); 
    Observable<Item> remote = remoteDataSource 
     .get(id) 
     .doOnNext(new Action1<Item>() { 
      @Override 
      public void call(final Item item) { 
       // save item to database and put to cache 
      } 
     }); 
    return Observable.concat(local, remote).first(); 
} 

Denn es mit einer Liste von IDs immer ich m mit der nächsten Methode:

@Override 
public Observable<List<Item>> getList(final List<String> ids) { 
    return Observable 
     .from(ids) 
     .flatMap(new Func1<String, Observable<Item>>() { 
      @Override 
      public Observable<Item> call(String id) { 
       return get(id); 
      } 
     }).toList(); 
} 

Und Abonnement in Fragment:

Subscription subscription = repository 
    .getList(ids) 
    .flatMap(new Func1<List<Item>, Observable<Item>>() { 
     @Override 
     public Observable<Item> call(List<Item> result) { 
      return Observable.from(result); 
     } 
    }) 
    .toList() 
    .subscribeOn(Schedulers.io()) 
    .observeOn(AndroidSchedulers.mainThread()) 
    .subscribe(new Observer<List<Item>>() { 
     @Override 
     public void onCompleted() { 

     } 

     @Override 
     public void onError(Throwable e) { 

     } 

     @Override 
     public void onNext(List<Item> result) { 
      // there get list of null objects 
     } 
}); 

Also, Hauptziel ist zuerst lokalen Speicher zu überprüfen und wenn es kein Element gibt - Anfrage an den Server. Aber jetzt, wenn das Element nicht existiert, bekomme ich null statt der Sendeanforderung.

Könnte jemand mir helfen zu verstehen, warum?

Antwort

1

Answer von Github:

Ihre Funktion beobachtbare get() gibt endlose beobachtbare weil mapToOneOrDefault tut nicht vollständig beobachtbar und reagiert auf Aktualisierungen der Datenbank. Sie müssen die Emission dieses Observable begrenzen, da operator concat auf onCompleted-Ereignis wartet.

Zum Beispiel sollte es wie folgt aussieht:

return Observable.concat(localSource.first(), remoteSource) 
    .filter(new Func1<Item, Boolean>() { 
     @Override 
     public Boolean call(Item item) { 
      return item!= null; 
     } 
    }); 
1

Der Aufruf von first() nach concat gibt natürlich das erste Element zurück, unabhängig davon, ob es gültig ist. Yout first() -Funktion sollte den Wert validieren und nur ein "gültiges" erstes Element übergeben.

Etwas wie:

public void test() { 
    Integer[] ids = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
    Observable.from(ids) 
      .flatMap(new Func1<Integer, Observable<String>>() { 
       @Override 
       public Observable<String> call(Integer id) { 
        return get(id); 
       } 
      }) 
      .toList() 
      .subscribeOn(Schedulers.io()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .subscribe(new Subscriber<List<String>>() { 
       @Override 
       public void onCompleted() { 

       } 

       @Override 
       public void onError(Throwable e) { 

       } 

       @Override 
       public void onNext(List<String> strings) { 

       } 
      }); 
} 

public Observable<String> get(int id) { 
    return Observable.concat(getLocal(id), getRemote(id)) 
      .first(new Func1<String, Boolean>() { 
       @Override 
       public Boolean call(String s) { 
        return s != null; 
       } 
      }); 
} 

public Observable<String> getLocal(int id) { 
    return Observable.just(id < 5 ? "fromLocal id:"+id : null); 
} 

public Observable<String> getRemote(int id) { 
    return Observable.just(id >= 5 ? "fromRemote id:"+id : null); 
} 

Wird u das Ergebnis bringen:

fromLocal id:1 
fromLocal id:2 
fromLocal id:3 
fromLocal id:4 
fromRemote id:5 
fromRemote id:6 
fromRemote id:7 
fromRemote id:8 
fromRemote id:9 
fromRemote id:10 
+0

Es half nicht. Einziger Unterschied, dass jetzt nichts mehr zurückkommt. –

+0

Sicher, Ihre Datenquelle Get (ID) gibt etwas anderes als null Werte zurück? –

+0

Seltsam, localSource gibt null zurück, und danach wird die Codeausführung gestoppt. Versuchte einfache Observable, die immer null zurückgibt und es funktioniert - gehe zum nächsten Schritt mit Netzwerkanforderung. Ich suche nach einem möglichen Problem mit SQLBrite .. –

Verwandte Themen