我正在使用RxAndroid,Retrofit和SqlBrite。
POJO类:
例如:file_path =“ ...... / videos / .mp4”
public class VideoResponse {
@SerializedName("files")
@Expose
private List<VideoFiles> files = null;
.....
}
public class VideoFiles {
@SerializedName("file_path")
@Expose
private String remotePath;
private String localPath;
.....
}
将列表从apiService传递到setLocalPath
。
@Inject
public RemoteDataSource(ApiService service,DownloadUtils downloadUtils) {
this.service = service;
this.downloadUtils = downloadUtils;
}
@Override
public Observable<List<VideoResponse>> getVideoResponse() {
return service.getVideoResponseFromServer()
.compose(RxUtils.applySchedulers())
==> .map(this::setVideoLocalPath)
.doOnSubscribe(disposable -> Timber.d("*** Video Sync Started....."))
.doOnError(throwable -> Timber.d("*** Video Sync Failed ...."))
.doOnComplete(() -> Timber.d(" *** Video Sync Complete...."));
}
将每个远程路径传递给DownloadUtils,并获取更改后的VideoResponse列表。
private List<VideoResponse> setVideoLocalPath(List<VideoResponse> videoResponses) {
for (VideoResponse r : videoResponses) {
for (VideoFiles file : r.getFiles()) {
downloadUtils.downloadVideoFromInternet(file, service);
}
}
return videoResponses;
}
下载和设置本地路径;
public class DownloadUtils {
public void downloadVideoFromInternet(VideoFiles video, ApiService service) {
service.downloadFileByUrl(video.getRemotePath())
.flatMap(processResponse("video", video.getFileTitle()))
.subscribe(handleVideoResult(video));
}
private Observer<? super File> handleVideoResult(VideoFiles video) {
return new Observer<File>() {
@Override
public void onSubscribe(Disposable d) {
Timber.i("*** Download File OnSubscribe ***");
}
@Override
public void onNext(File file) {
Timber.d(" $$$$ Video File Path $$$ -> %s", file.getAbsolutePath());
video.setLocalPath(file.getAbsolutePath());
}
@Override
public void onError(Throwable e) {
Timber.e(e);
}
@Override
public void onComplete() {
Timber.i("*** Download File Completed ****");
}
};
}
private Function<Response<ResponseBody>, Observable<File>> processResponse(String folderName, String fileTitle) {
return response -> saveToDisk(response, folderName, fileTitle);
}
private Observable<File> saveToDisk(Response<ResponseBody> response, String fileTitle, String folderName) {
return Observable.create(subscriber -> {
try {
File file = new File("/data/aster/" + folderName + fileTitle);
if (!file.exists()) {
file.mkdirs();
}
BufferedSink bufferedSink = Okio.buffer(Okio.sink(file));
bufferedSink.writeAll(response.body().source());
bufferedSink.close();
subscriber.onNext(file);
subscriber.onComplete();
} catch (IOException e) {
e.printStackTrace();
subscriber.onError(e);
}
});
}
}
问题是视频文件未下载,每个视频都停止订阅。
将值传递给setLocalVideoPath
后,下载仍未完成,我得到NetworkOnMainThreadException
且应用程序崩溃了。.是否有更好的方法来实现此逻辑。.!!敬请帮助。
答案 0 :(得分:1)
如果RxUtils.applySchedulers正在应用以下内容,那么在您进行映射操作并随后点击service.downloadFileByUrl时,它将在主线程上执行。
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
如果您在地图操作之后移动了observeOn调用,则service.downloadFileByUrl应该在主线程(即
)上执行。@Override
public Observable<List<VideoResponse>> getVideoResponse() {
return service.getVideoResponseFromServer()
.subscribeOn(Schedulers.io())
.map(this::setVideoLocalPath)
.observeOn(AndroidSchedulers.mainThread());
.doOnSubscribe(disposable -> Timber.d("*** Video Sync Started....."))
.doOnError(throwable -> Timber.d("*** Video Sync Failed ...."))
.doOnComplete(() -> Timber.d(" *** Video Sync Complete...."));
}
答案 1 :(得分:1)
问题在于您执行操作的顺序,特别是这里
....
.compose(RxUtils.applySchedulers())
.map(this::setVideoLocalPath)
...
如果查看RxUtils.applySchedulers()
的源代码,您会发现转换器看起来像这样:
static Observable.Transformer schedulersTransformer = new Observable.Transformer<Object, Object>() {
@Override public Observable<Object> call(Observable<Object> observable) {
return observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
因此,observeOn(AndroidSchedulers.mainThread())
将执行工作的线程切换到主线程,而当map
进行下一步操作时,它将在主线程上执行工作。我看不出您的map
运算符后来应该走的任何原因。只需更改顺序如下:
....
.map(this::setVideoLocalPath)
.compose(RxUtils.applySchedulers())
...
在这里,执行链是固定的,您的map
运算符将在io
线程上工作。另外,请注意,您的doOnSubscribe
在主线程上执行工作,之后 compose(RxUtils.applySchedulers())
。