You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
18 KiB
448 lines
18 KiB
package com.novel.read.service;
|
|
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.os.Binder;
|
|
import android.os.Handler;
|
|
import android.os.IBinder;
|
|
import android.text.TextUtils;
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
import com.mango.mangolib.event.EventManager;
|
|
import com.novel.read.R;
|
|
import com.novel.read.base.BaseService;
|
|
import com.novel.read.event.DeleteResponseEvent;
|
|
import com.novel.read.event.DeleteTaskEvent;
|
|
import com.novel.read.event.RxBus;
|
|
import com.novel.read.http.AccountManager;
|
|
import com.novel.read.model.db.BookChapterBean;
|
|
import com.novel.read.model.db.DownloadTaskBean;
|
|
import com.novel.read.model.db.dbManage.BookManager;
|
|
import com.novel.read.model.db.dbManage.BookRepository;
|
|
import com.novel.read.utlis.LocalManageUtil;
|
|
import com.novel.read.utlis.LogUtils;
|
|
import com.novel.read.utlis.NetworkUtils;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
|
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
import io.reactivex.disposables.Disposable;
|
|
|
|
/**
|
|
* Created by newbiechen on 17-5-10.
|
|
*/
|
|
|
|
public class DownloadService extends BaseService {
|
|
private static final String TAG = "DownloadService";
|
|
//加载状态
|
|
private static final int LOAD_ERROR = -1;
|
|
private static final int LOAD_NORMAL = 0;
|
|
private static final int LOAD_PAUSE = 1;
|
|
private static final int LOAD_DELETE = 2; //正在加载时候,用户删除收藏书籍的情况。
|
|
|
|
//下载状态
|
|
public static final int STATUS_CONTINUE = DownloadTaskBean.STATUS_LOADING;
|
|
public static final int STATUS_PAUSE = DownloadTaskBean.STATUS_PAUSE;
|
|
|
|
//线程池
|
|
private final ExecutorService mSingleExecutor = Executors.newSingleThreadExecutor();
|
|
//加载队列
|
|
private final List<DownloadTaskBean> mDownloadTaskQueue = Collections.synchronizedList(new ArrayList<>());
|
|
//Handler
|
|
private Handler mHandler;
|
|
|
|
//包含所有的DownloadTask
|
|
private List<DownloadTaskBean> mDownloadTaskList;
|
|
|
|
private OnDownloadListener mDownloadListener;
|
|
private boolean isBusy = false;
|
|
private boolean isCancel = false;
|
|
|
|
@Override
|
|
protected void attachBaseContext(Context base) {
|
|
super.attachBaseContext(LocalManageUtil.setLocal(base));
|
|
}
|
|
|
|
@Override
|
|
public void onCreate() {
|
|
super.onCreate();
|
|
mHandler = new Handler(getMainLooper());
|
|
//从数据库中获取所有的任务
|
|
mDownloadTaskList = BookRepository
|
|
.getInstance()
|
|
.getDownloadTaskList();
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public IBinder onBind(Intent intent) {
|
|
return new TaskBuilder();
|
|
}
|
|
|
|
@Override
|
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
|
|
|
//接受创建的DownloadTask
|
|
Disposable disposable = RxBus.getInstance()
|
|
.toObservable(DownloadTaskBean.class)
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe(
|
|
(event) -> {
|
|
//判断任务是否为轮询标志
|
|
//判断任务是否存在,并修改任务
|
|
if (TextUtils.isEmpty(event.getBookId()) || !checkAndAlterDownloadTask(event)) {
|
|
addToExecutor(event);
|
|
}
|
|
}
|
|
);
|
|
addDisposable(disposable);
|
|
|
|
//是否删除数据的问题
|
|
Disposable deleteDisp = RxBus.getInstance()
|
|
.toObservable(DeleteTaskEvent.class)
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe(
|
|
(event) -> {
|
|
//判断是否该数据存在加载列表中
|
|
boolean isDelete = true;
|
|
for (DownloadTaskBean bean : mDownloadTaskQueue) {
|
|
if (bean.getBookId().equals(event.collBook.getId())) {
|
|
isDelete = false;
|
|
break;
|
|
}
|
|
}
|
|
//如果不存在则删除List中的task
|
|
if (isDelete) {
|
|
//
|
|
Iterator<DownloadTaskBean> taskIt = mDownloadTaskList.iterator();
|
|
while (taskIt.hasNext()) {
|
|
DownloadTaskBean task = taskIt.next();
|
|
if (task.getBookId().equals(event.collBook.getId())) {
|
|
taskIt.remove();
|
|
}
|
|
}
|
|
}
|
|
//返回状态
|
|
RxBus.getInstance().post(new DeleteResponseEvent(isDelete, event.collBook));
|
|
}
|
|
);
|
|
addDisposable(deleteDisp);
|
|
return super.onStartCommand(intent, flags, startId);
|
|
}
|
|
|
|
|
|
/**
|
|
* 1. 查看是否任务已存在
|
|
* 2. 修改DownloadTask的 taskName 和 list
|
|
*
|
|
* @return
|
|
*/
|
|
private boolean checkAndAlterDownloadTask(DownloadTaskBean newTask) {
|
|
boolean isExist = false;
|
|
for (DownloadTaskBean downloadTask : mDownloadTaskList) {
|
|
//如果不相同则不往下执行,往下执行都是存在相同的情况
|
|
if (!downloadTask.getTaskName().equals(newTask.getTaskName())) continue;
|
|
|
|
if (downloadTask.getStatus() == DownloadTaskBean.STATUS_FINISH) {
|
|
//判断是否newTask是已完成
|
|
if (downloadTask.getLastChapter() == newTask.getLastChapter()) {
|
|
isExist = true;
|
|
//发送回去已缓存
|
|
postMessage(getString(R.string.cached));
|
|
}
|
|
//判断,是否已完成的章节的起始点比新Task大,如果更大则表示新Task中的该章节已被加载,所以需要剪切
|
|
else if (downloadTask.getLastChapter() > (newTask.getLastChapter() - newTask.getBookChapterList().size())) {
|
|
if (downloadTask.getLastChapter() > newTask.getLastChapter()) {
|
|
isExist = true;
|
|
//发送回去已缓存
|
|
postMessage(getString(R.string.cached));
|
|
} else {
|
|
//删除掉已经完成的章节
|
|
List<BookChapterBean> remainChapterBeans = newTask.getBookChapterList().subList(downloadTask.getLastChapter(), newTask.getLastChapter());
|
|
String taskName = newTask.getTaskName()
|
|
+ getString(R.string.nb_download_chapter_scope,
|
|
downloadTask.getLastChapter(), newTask.getLastChapter());
|
|
//重置任务
|
|
newTask.setBookChapters(remainChapterBeans);
|
|
newTask.setTaskName(taskName);
|
|
|
|
//发送添加到任务的提示
|
|
postMessage(getString(R.string.cache_success));
|
|
}
|
|
}
|
|
}
|
|
//表示该任务已经在 下载、等待、暂停、网络错误中
|
|
else {
|
|
isExist = true;
|
|
//发送回去:已经在加载队列中。
|
|
postMessage(getString(R.string.task_exist));
|
|
}
|
|
}
|
|
//重置名字
|
|
if (!isExist) {
|
|
String taskName = newTask.getTaskName()
|
|
+ getString(R.string.nb_download_chapter_scope,
|
|
1, newTask.getLastChapter());
|
|
newTask.setTaskName(taskName);
|
|
postMessage(getString(R.string.cache_success));
|
|
}
|
|
return isExist;
|
|
}
|
|
|
|
private void addToExecutor(DownloadTaskBean taskEvent) {
|
|
|
|
//判断是否为轮询请求
|
|
if (!TextUtils.isEmpty(taskEvent.getBookId())) {
|
|
|
|
if (!mDownloadTaskList.contains(taskEvent)) {
|
|
//加入总列表中,表示创建,修改CollBean的状态。
|
|
mDownloadTaskList.add(taskEvent);
|
|
}
|
|
// 添加到下载队列
|
|
mDownloadTaskQueue.add(taskEvent);
|
|
}
|
|
|
|
// 从队列顺序取出第一条下载
|
|
if (mDownloadTaskQueue.size() > 0 && !isBusy) {
|
|
isBusy = true;
|
|
executeTask(mDownloadTaskQueue.get(0));
|
|
}
|
|
}
|
|
|
|
private void executeTask(DownloadTaskBean taskEvent) {
|
|
Runnable runnable = () -> {
|
|
|
|
taskEvent.setStatus(DownloadTaskBean.STATUS_LOADING);
|
|
|
|
int result = LOAD_NORMAL;
|
|
List<BookChapterBean> bookChapterBeans = taskEvent.getBookChapters();
|
|
|
|
//调用for循环,下载数据 //todo
|
|
// for (int i=taskEvent.getCurrentChapter(); i<bookChapterBeans.size();++i) {
|
|
for (int i = taskEvent.getCurrentChapter(); i <= taskEvent.getLastChapter() && i < bookChapterBeans.size(); ++i) {
|
|
|
|
BookChapterBean bookChapterBean = bookChapterBeans.get(i);
|
|
//首先判断该章节是否曾经被加载过 (从文件中判断)
|
|
if (BookManager.isChapterCached(taskEvent.getBookId(), bookChapterBean.getTitle())) {
|
|
|
|
//设置任务进度
|
|
taskEvent.setCurrentChapter(i);
|
|
|
|
//章节加载完成
|
|
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_LOADING, i + "");
|
|
|
|
//无需进行下一步
|
|
continue;
|
|
}
|
|
|
|
//判断网络是否出问题
|
|
if (!NetworkUtils.isAvailable()) {
|
|
//章节加载失败
|
|
result = LOAD_ERROR;
|
|
break;
|
|
}
|
|
|
|
if (isCancel) {
|
|
result = LOAD_PAUSE;
|
|
isCancel = false;
|
|
break;
|
|
}
|
|
|
|
//加载数据
|
|
result = loadChapter(taskEvent.getBookId(), bookChapterBean);
|
|
//章节加载完成
|
|
if (result == LOAD_NORMAL) {
|
|
taskEvent.setCurrentChapter(i);
|
|
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_LOADING, i + "");
|
|
}
|
|
//章节加载失败
|
|
else {
|
|
//遇到错误退出
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (result == LOAD_NORMAL) {
|
|
//存储DownloadTask的状态
|
|
taskEvent.setStatus(DownloadTaskBean.STATUS_FINISH);//Task的状态
|
|
taskEvent.setCurrentChapter(taskEvent.getBookChapters().size());//当前下载的章节数量
|
|
taskEvent.setSize(BookManager.getBookSize(taskEvent.getBookId()));//Task的大小
|
|
|
|
//发送完成状态
|
|
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_FINISH, getString(R.string.download_success));
|
|
} else if (result == LOAD_ERROR) {
|
|
taskEvent.setStatus(DownloadTaskBean.STATUS_ERROR);//Task的状态
|
|
//任务加载失败
|
|
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_ERROR, getString(R.string.download_error));
|
|
} else if (result == LOAD_PAUSE) {
|
|
taskEvent.setStatus(DownloadTaskBean.STATUS_PAUSE);//Task的状态
|
|
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_PAUSE, getString(R.string.download_pause));
|
|
} else if (result == LOAD_DELETE) {
|
|
//没想好怎么做
|
|
}
|
|
|
|
//存储状态
|
|
BookRepository.getInstance().saveDownloadTask(taskEvent);
|
|
|
|
//轮询下一个事件,用RxBus用来保证事件是在主线程
|
|
|
|
//移除完成的任务
|
|
mDownloadTaskQueue.remove(taskEvent);
|
|
//设置为空闲
|
|
isBusy = false;
|
|
//轮询
|
|
post(new DownloadTaskBean());
|
|
};
|
|
mSingleExecutor.execute(runnable);
|
|
}
|
|
|
|
private int loadChapter(String folderName, BookChapterBean bean) {
|
|
//加载的结果参数
|
|
final int[] result = {LOAD_NORMAL};
|
|
|
|
//问题:(这里有个问题,就是body其实比较大,如何获取数据流而不是对象,)是不是直接使用OkHttpClient交互会更好一点
|
|
Disposable disposable = AccountManager.getInstance()
|
|
.getChapterInfo(bean.getId())
|
|
//表示在当前环境下执行
|
|
.subscribe(
|
|
chapterInfo -> {
|
|
//TODO:这里文件的名字用的是BookChapter的title,而不是chapter的title。
|
|
//原因是Chapter的title可能重复,但是BookChapter的title不会重复
|
|
//BookChapter的title = 卷名 + 章节名 chapter 的 title 就是章节名。。
|
|
BookRepository.getInstance().saveChapterInfo(folderName, bean.getTitle(), chapterInfo.getBody());
|
|
},
|
|
e -> {
|
|
//当前进度加载错误(这里需要判断是什么问题,根据相应的问题做出相应的回答)
|
|
LogUtils.e(e);
|
|
//设置加载结果
|
|
result[0] = LOAD_ERROR;
|
|
}
|
|
);
|
|
addDisposable(disposable);
|
|
return result[0];
|
|
}
|
|
|
|
private void postDownloadChange(DownloadTaskBean task, int status, String msg) {
|
|
if (mDownloadListener != null && msg != null) {
|
|
int position = mDownloadTaskList.indexOf(task);
|
|
//通过handler,切换回主线程
|
|
mHandler.post(() -> mDownloadListener.onDownloadChange(
|
|
position, status, msg)
|
|
);
|
|
}
|
|
}
|
|
|
|
private void postMessage(String msg) {
|
|
// RxBus.getInstance().post(new DownloadMessage(msg));
|
|
EventManager.Companion.getInstance().postEvent(new DownloadMessage(msg));
|
|
}
|
|
|
|
private void post(DownloadTaskBean task) {
|
|
RxBus.getInstance().post(task);
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean onUnbind(Intent intent) {
|
|
|
|
mDownloadListener = null;
|
|
return super.onUnbind(intent);
|
|
}
|
|
|
|
class TaskBuilder extends Binder implements IDownloadManager {
|
|
@Override
|
|
public List<DownloadTaskBean> getDownloadTaskList() {
|
|
return Collections.unmodifiableList(mDownloadTaskList);
|
|
}
|
|
|
|
@Override
|
|
public void setOnDownloadListener(OnDownloadListener listener) {
|
|
mDownloadListener = listener;
|
|
}
|
|
|
|
@Override
|
|
public void setDownloadStatus(String taskName, int status) {
|
|
//修改某个Task的状态
|
|
switch (status) {
|
|
//加入缓存队列
|
|
case DownloadTaskBean.STATUS_WAIT:
|
|
for (int i = 0; i < mDownloadTaskList.size(); ++i) {
|
|
DownloadTaskBean bean = mDownloadTaskList.get(i);
|
|
if (taskName.equals(bean.getTaskName())) {
|
|
bean.setStatus(DownloadTaskBean.STATUS_WAIT);
|
|
mDownloadListener.onDownloadResponse(i, DownloadTaskBean.STATUS_WAIT);
|
|
addToExecutor(bean);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
//从缓存队列中删除
|
|
case DownloadTaskBean.STATUS_PAUSE:
|
|
Iterator<DownloadTaskBean> it = mDownloadTaskQueue.iterator();
|
|
while (it.hasNext()) {
|
|
DownloadTaskBean bean = it.next();
|
|
if (bean.getTaskName().equals(taskName)) {
|
|
if (bean.getStatus() == DownloadTaskBean.STATUS_LOADING
|
|
&& bean.getTaskName().equals(taskName)) {
|
|
isCancel = true;
|
|
break;
|
|
} else {
|
|
bean.setStatus(DownloadTaskBean.STATUS_PAUSE);
|
|
mDownloadTaskQueue.remove(bean);
|
|
int position = mDownloadTaskList.indexOf(bean);
|
|
mDownloadListener.onDownloadResponse(position, DownloadTaskBean.STATUS_PAUSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setAllDownloadStatus(int status) {
|
|
//修改所有Task的状态
|
|
}
|
|
|
|
//首先判断是否在加载队列中。
|
|
//如果在加载队列中首先判断是否正在下载,
|
|
//然后判断是否在完成队列中。
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
super.onDestroy();
|
|
}
|
|
|
|
|
|
public interface IDownloadManager {
|
|
List<DownloadTaskBean> getDownloadTaskList();
|
|
|
|
void setOnDownloadListener(OnDownloadListener listener);
|
|
|
|
void setDownloadStatus(String taskName, int status);
|
|
|
|
void setAllDownloadStatus(int status);
|
|
}
|
|
|
|
public interface OnDownloadListener {
|
|
/**
|
|
* @param pos : Task在item中的位置
|
|
* @param status : Task的状态
|
|
* @param msg: 传送的Msg
|
|
*/
|
|
void onDownloadChange(int pos, int status, String msg);
|
|
|
|
/**
|
|
* 回复
|
|
*/
|
|
void onDownloadResponse(int pos, int status);
|
|
}
|
|
}
|
|
|