package com.kunfei.bookshelf.model.task; import android.text.TextUtils; import com.hwangjr.rxbus.RxBus; import com.kunfei.bookshelf.base.observer.MyObserver; import com.kunfei.bookshelf.bean.BookChapterBean; import com.kunfei.bookshelf.bean.BookContentBean; import com.kunfei.bookshelf.bean.BookShelfBean; import com.kunfei.bookshelf.bean.DownloadBookBean; import com.kunfei.bookshelf.bean.DownloadChapterBean; import com.kunfei.bookshelf.constant.RxBusTag; import com.kunfei.bookshelf.help.BookshelfHelp; import com.kunfei.bookshelf.model.WebBookModel; import com.kunfei.bookshelf.model.impl.IDownloadTask; import java.util.ArrayList; import java.util.List; import io.reactivex.Observable; import io.reactivex.ObservableOnSubscribe; import io.reactivex.Scheduler; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; public abstract class DownloadTaskImpl implements IDownloadTask { private int id; private boolean isDownloading = false; private DownloadBookBean downloadBook; private List<DownloadChapterBean> downloadChapters; private boolean isLocked = false; private CompositeDisposable disposables; protected DownloadTaskImpl(int id, DownloadBookBean downloadBook) { this.id = id; this.downloadBook = downloadBook; downloadChapters = new ArrayList<>(); disposables = new CompositeDisposable(); Observable.create((ObservableOnSubscribe<DownloadBookBean>) emitter -> { List<BookChapterBean> chapterList = BookshelfHelp.getChapterList(downloadBook.getNoteUrl()); if (!chapterList.isEmpty()) { for (int i = downloadBook.getStart(); i <= downloadBook.getEnd(); i++) { DownloadChapterBean chapter = new DownloadChapterBean(); chapter.setBookName(downloadBook.getName()); chapter.setDurChapterIndex(chapterList.get(i).getDurChapterIndex()); chapter.setDurChapterName(chapterList.get(i).getDurChapterName()); chapter.setDurChapterUrl(chapterList.get(i).getDurChapterUrl()); chapter.setNoteUrl(chapterList.get(i).getNoteUrl()); chapter.setTag(chapterList.get(i).getTag()); if (!BookshelfHelp.isChapterCached(chapter.getBookName(), chapter.getTag(), chapter, false)) { downloadChapters.add(chapter); } } } downloadBook.setDownloadCount(downloadChapters.size()); emitter.onNext(downloadBook); }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new MyObserver<DownloadBookBean>() { @Override public void onSubscribe(Disposable d) { disposables.add(d); } @Override public void onNext(DownloadBookBean downloadBook) { if (downloadBook.isValid()) { onDownloadPrepared(downloadBook); whenProgress(downloadChapters.get(0)); } else { onDownloadComplete(downloadBook); } } @Override public void onError(Throwable e) { downloadBook.setValid(false); onDownloadError(downloadBook); } }); } @Override public int getId() { return id; } @Override public void startDownload(Scheduler scheduler) { if (isFinishing()) return; if (disposables.isDisposed()) { disposables = new CompositeDisposable(); } isDownloading = true; toDownload(scheduler); } @Override public void stopDownload() { if (!disposables.isDisposed()) { disposables.dispose(); } if (isDownloading) { isDownloading = false; onDownloadComplete(downloadBook); } if (!isFinishing()) { downloadChapters.clear(); } } @Override public boolean isDownloading() { return isDownloading; } @Override public boolean isFinishing() { return downloadChapters.isEmpty(); } @Override public DownloadBookBean getDownloadBook() { return downloadBook; } private synchronized void toDownload(Scheduler scheduler) { if (isFinishing()) { return; } if (!isLocked) { getDownloadingChapter() .subscribe(new MyObserver<DownloadChapterBean>() { @Override public void onNext(DownloadChapterBean chapterBean) { if (chapterBean != null) { downloading(chapterBean, scheduler); } else { isLocked = true; } } @Override public void onError(Throwable e) { onDownloadError(downloadBook); } }); } } /** * @return 章节下载信息 */ private Observable<DownloadChapterBean> getDownloadingChapter() { return Observable.create(emitter -> { DownloadChapterBean next = null; List<DownloadChapterBean> temp = new ArrayList<>(downloadChapters); for (DownloadChapterBean data : temp) { boolean cached = BookshelfHelp.isChapterCached(data.getBookName(), data.getTag(), data, false); if (cached) { removeFromDownloadList(data); } else { next = data; break; } } emitter.onNext(next); }); } /** * 下载 */ private synchronized void downloading(DownloadChapterBean chapter, Scheduler scheduler) { whenProgress(chapter); BookShelfBean bookShelfBean = BookshelfHelp.getBook(chapter.getNoteUrl()); Observable.create((ObservableOnSubscribe<DownloadChapterBean>) e -> { if (!BookshelfHelp.isChapterCached(chapter.getBookName(), chapter.getTag(), chapter, false)) { e.onNext(chapter); } else { e.onError(new Exception("cached")); } e.onComplete(); }) .flatMap(result -> { return WebBookModel.getInstance().getBookContent(bookShelfBean, chapter, null); }) .subscribeOn(scheduler) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new MyObserver<BookContentBean>() { @Override public void onSubscribe(Disposable d) { disposables.add(d); } @Override public void onNext(BookContentBean bookContentBean) { RxBus.get().post(RxBusTag.CHAPTER_CHANGE, bookContentBean); removeFromDownloadList(chapter); whenNext(scheduler, true); } @Override public void onError(Throwable e) { removeFromDownloadList(chapter); if (TextUtils.equals(e.getMessage(), "cached")) { whenNext(scheduler, false); } else { whenError(scheduler); } } }); } /** * 从下载列表移除 */ private synchronized void removeFromDownloadList(DownloadChapterBean chapterBean) { downloadChapters.remove(chapterBean); } private void whenNext(Scheduler scheduler, boolean success) { if (!isDownloading) { return; } if (success) { downloadBook.successCountAdd(); } if (isFinishing()) { stopDownload(); onDownloadComplete(downloadBook); } else { onDownloadChange(downloadBook); toDownload(scheduler); } } private void whenError(Scheduler scheduler) { if (!isDownloading) { return; } if (isFinishing()) { stopDownload(); if (downloadBook.getSuccessCount() == 0) { onDownloadError(downloadBook); } else { onDownloadComplete(downloadBook); } } else { toDownload(scheduler); } } private void whenProgress(DownloadChapterBean chapterBean) { if (!isDownloading) { return; } onDownloadProgress(chapterBean); } }