因此,我的任务是将设备的位置信息(如果更改)推送到远程服务器Json API服务。如果远程服务器不可用,我的DatabaseManager必须将它们保存到本地数据库。
这是我的Retrofit 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发出)。它的setLocation()方法更新currentLocation变量,然后将其放入locationBuffer,而不是检查缓冲区的大小,而不是缓冲区的大小超过我的MAX_BUFFER_SIZE变量,它会触发locationBufferChanged.onNext(使用locationBuffer的副本作为参数),然后清除它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:
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();
}
}
}
我的应用程序的主要目标:
通过Retrofit将所有已侦听的LocationPoints写入HTTP服务器。如果远程服务器因某种原因突然停机(或者互联网连接丢失),我的应用程序应该无缝地将新的locationPoints写入本地数据库。当服务器(或互联网)启动时,某些机制应该将已保存的本地数据提供给Retrofit的呼叫。
所以,我的问题是:
答案 0 :(得分:0)
有趣的任务!首先:您不需要创建DB来存储这么小的信息。 Android可以存储任何Serializable
数据。
因此,为了保存本地数据包模型,如:
public class MyLocation implements Serializable {
@Nonnull
private final String id;
private final Location location;
private final boolean isSynced;
// constructor...
// getters...
}
Singleton类:
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。它有很多“很酷的工具”(btw,来自那里的UserPref类中的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
}
});