2016-10-30 1 views
1

私の仕事は、デバイスのロケーション情報が変更されたときにリモートサーバーのJson APIサービスにプッシュすることです。リモートサーバが利用できない場合、私のDatabaseManagerはそれらをローカルデータベースに保存する必要があります。ここでどのように(RxJava)Observableから放出されるデータをハンドラが処理するかを適切に設定しますか?

は私のレトロフィットAPIです:

public interface GpsService { 
     @POST("/v1/savelocationbatch") 
     SaveResponse saveLocationBatch(@Body LocationBatch locationBatch); 
    } 

    Retrofit retrofit = new Retrofit.Builder() 
     .baseUrl(myBaseUrl) 
     .addConverterFactory(GsonConverterFactory.create()) 
     .build(); 

    GpsService service = retrofit.create(GpsService.class); 

そして、POJOクラス:

public class LocationBatch{ 

     @SerializedName("LocationPointList") 
     ArrayList<LocationPoint> locationPointList; 
     @SerializedName("ClientId") 
     String clientId; 
     @SerializedName("ClientSecret") 
     String clientSecret; 

     //setter & getter 
    } 

マイLocationPointモデル:

@Table(name="LocationPoints", id = "_id") 
    public class LocationPoint extends Model { 

     @SerializedName("Latitude") 
     @Column(name="latitude") 
     public Double latitude; 

     @SerializedName("Longitude") 
     @Column(name="longitude") 
     public Double longitude; 

     @SerializedName("Altitude") 
     @Column(name="altitude") 
     public Double altitude; 

     //... setters, getters etc 
} 

私の最後の場所のすべてがに格納されていますCurrentLocationHolderシングルトン(バッチ送信/保存用) DB/Observableからの放射)。バッファのサイズがMAX_BUFFER_SIZE変数を超えた場合、locationBufferChanged.onNext(引数としてlocationBufferのコピーを使用)を発生させるよりも、setLocation()メソッドはcurrentLocation変数を更新してlocationBufferに格納します。

public class DatabaseManager {  
     private Subscription locationBufferSubscription; 
     private static DatabaseManager instance;  
     public static void InitInstance() { 
      if (instance == null) 
       instance = new DatabaseManager(); 
      } 
     } 

     public void saveToDb(ArrayList<LocationPoint> locArray){ 
      ActiveAndroid.beginTransaction(); 
      try { 
       for (int i = 0; i < locArray.size(); i++) { 
        locArray.get(i).save(); 
       } 
       ActiveAndroid.setTransactionSuccessful(); 
      } 
      finally { 
       ActiveAndroid.endTransaction(); 
      } 
     } 
    } 

私のアプリケーションの主な目標:

listeneの全てを書き込むにはlocationBuffer ...

public class CurrentLocationHolder { 

     private List<LocationPoint> locationBuffer = 
          Collections.synchronizedList(new ArrayList<>()); 
     private LocationPoint currentLocation; 
     private final PublishSubject<List<LocationPoint>> locationBufferFull = 
          PublishSubject.create(); 

     public Observable<List<LocationPoint>> 
          observeLocationBufferFull(boolean emitCurrentValue) { 
       return emitCurrentValue ? 
        locationBufferFull.startWith(locationBuffer) : 
        locationBufferFull; 
      } 

     public void setLocation(LocationPoint point) { 
      this.currentLocation = point; 
      locationBuffer.add(point); 
      if (locationBuffer.size() >= MAX_BUFFER_SIZE) { 
       locationBufferChanged.onNext(new ArrayList<>(this.locationBuffer)); 
      } 
      locationBuffer.clear(); 
     } 
    } 

そして、ここでは私のDatabaseManagerですd Retrofitを介してHTTPサーバーにLocationPointを転送します。何らかの理由でリモートサーバーが突然停止する(またはインターネット接続が失われる)場合、私のアプリケーションは新しいlocationPointsをシームレスにローカルデータベースに書き込む必要があります。サーバー(またはインターネット)が起動すると、Retrofitの呼び出しに保存されたローカルデータが提供されるメカニズムがあります。

だから、私の質問は以下のとおりです。

  1. レトロフィットサービスに正常に一覧を放出するのRx-被監視オブジェクトを作成するには、サーバー(またはインターネット)がダウンしたとき、それは提供する必要がありますどのように未保存のLocationPointsをDatabaseManager.saveToDb()メソッドに変換しますか?
  2. インターネット接続またはサーバーの「アップ」状態を取得するにはどうすればよいですか? Observableを作成してリモートサーバにpingを実行するとよいでしょうか?その結果、サブスクライバにブール値を送信する必要がありますか?この動作を実装する最善の方法は何ですか?
  3. インターネット接続(サーバ)が「アップ」になったときにローカルに保存されたデータ(ローカルDBから)でRetrofitコールをエンキューする簡単な方法はありますか?
  4. サーバー側で自分のLocationPointを失わないようにするにはどうすればよいですか? !?(最終的には私のクライアントアプリはそれらのすべてを送信する必要があり
  5. 私が何か間違ったことをやって、私は、Android、Javaと特にRxJavaに
    に初心者アム...

答えて

0

興味深いタスクまず第一に!:そのような小さな情報を格納するためのDBを作成する必要はありません。AndroidはSerializableのデータを格納するのに適しています。

public class MyLocation implements Serializable { 

    @Nonnull 
    private final String id; 
    private final Location location; 
    private final boolean isSynced; 

    // constructor... 
    // getters... 
} 

シングルトンクラス:

public class UserPreferences { 
    private static final String LOCATIONS = "locations"; 
    @Nonnull 
    private final SharedPreferences preferences; 
    @Nonnull 
    private final Gson gson; 
    private final PublishSubject<Object> locationRefresh = PublishSubject.create(); 

public void addLocation(MyLocation location) { 
    final String json = preferences.getString(LOCATIONS, null); 

    final Type type = new TypeToken<List<MyLocation>>() { 
    }.getType(); 

    final List<MyLocation> list; 
    if (!Strings.isNullOrEmpty(json)) { 
     list = gson.fromJson(json, type); 
    } else { 
     list = new ArrayList<MyLocation>(); 
    } 
    list.add(lication); 

    final String newJson = gson.toJson(set); 
    preferences.edit().putString(LOCATIONS, newJson).commit(); 
    locationRefresh.onNext(null); 
} 

private List<String> getLocations() { 
    final String json = preferences.getString(LOCATIONS, null); 

    final Type type = new TypeToken<List<MyLocation>>() { 
    }.getType(); 

    final List<MyLocation> list = new ArrayList<MyLocation>(); 
    if (!Strings.isNullOrEmpty(json)) { 
     list.addAll(gson.<List<MyLocation>>fromJson(json, type)); 
    } 

    return list; 
} 

@Nonnull 
public Observable<List<MyLocation>> getLocationsObservable() { 
    return Observable 
      .defer(new Func0<Observable<List<MyLocation>>>() { 
       @Override 
       public Observable<List<MyLocation>> call() { 
        return Observable.just(getLocations()) 
          .filter(Functions1.isNotNull()); 
       } 
      }) 
      .compose(MoreOperators.<List<MyLocation>>refresh(locationRefresh)); 
} 

// also You need to create getLocationsObservable() and getLocations() methods but only for not synced Locations. 

} 

変更:のようなローカルデータクレートモデルを保存するので、

public interface GpsService { 
    @POST("/v1/savelocationbatch") 
    Observable<SaveResponse> saveLocationBatch(@Body LocationBatch locationBatch); 
} 

今、最も興味深い...それはすべての作品作り。 RxJavaにはextentionがあります。それは、そこからUserPrefクラスの "クールなツール"(btw、MoreOperators)が多く、改造エラーを処理するためのものもあります。

したがって、Observable saveLocationObservableが何かを放射するとき、場所の節約が起こると仮定しましょう。その場合、コードは次のようになります。

final Observable<ResponseOrError<SaveResponse>> responseOrErrorObservable = saveLocationObservable 
     .flatMap(new Func1<MyLocation, Observable<ResponseOrError<SaveResponse>>>() { 
      @Override 
      public Observable<ResponseOrError<SaveResponse>> call(MyLocation myLocation) { 
       final LocationBatch locationBatch = LocationBatch.fromMyLocation(myLocation); // some method to convert local location to requesr one 
       return saveLocationBatch(locationBatch) 
         .observeOn(uiScheduler) 
         .subscribeOn(networkScheduler) 
         .compose(ResponseOrError.<SaveResponse>toResponseOrErrorObservable()); 
      } 

     }) 
     .replay(1) 
     .refCount(); 
final Observable<Throwable> error = responseOrErrorObservable 
    .compose(ResponseOrError.<SaveResponse>onlyError()) 
    .withLatestFrom(saveLocationObservable, Functions2.<MyLocation>secondParam()) 
    .subscribe(new Action1<MyLocation>() { 
      @Override 
      public void call(MyLocation myLocation) { 
        // save location to UserPref with flag isSynced=flase 
      } 
     }); 
final Observable<UserInfoResponse> success = responseOrErrorObservable 
    .compose(ResponseOrError.<SaveResponse>onlySuccess()) 
    .subscribe(new Action1<SaveResponse>() { 
      @Override 
      public void call(SaveResponse response) { 
       // save location to UserPref with flag isSynced=true 
      } 
     }); 
関連する問題