diff --git a/app/src/main/java/com/monke/monkeybook/service/DownloadService.java b/app/src/main/java/com/monke/monkeybook/service/DownloadService.java index df87ad1..cbeb97b 100644 --- a/app/src/main/java/com/monke/monkeybook/service/DownloadService.java +++ b/app/src/main/java/com/monke/monkeybook/service/DownloadService.java @@ -1,4 +1,3 @@ -//Copyright (c) 2017. 章钦豪. All rights reserved. package com.monke.monkeybook.service; import android.app.NotificationManager; @@ -12,6 +11,7 @@ import android.os.Looper; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.widget.Toast; + import com.hwangjr.rxbus.RxBus; import com.hwangjr.rxbus.annotation.Subscribe; import com.hwangjr.rxbus.annotation.Tag; @@ -30,7 +30,9 @@ import com.monke.monkeybook.dao.DbHelper; import com.monke.monkeybook.dao.DownloadChapterBeanDao; import com.monke.monkeybook.model.impl.WebBookModelImpl; import com.monke.monkeybook.view.impl.MainActivity; + import java.util.List; + import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; @@ -41,18 +43,24 @@ import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; import io.reactivex.schedulers.Schedulers; +// DownloadService类,继承自Service,用于处理书籍下载相关的业务逻辑,如启动、暂停、取消下载等操作 public class DownloadService extends Service { + // 用于管理通知的显示和取消等操作 private NotificationManager notifyManager; + // 通知的唯一标识符 private int notifiId = 19931118; + // 标记是否开始下载 private Boolean isStartDownload = false; + // 标记是否已经初始化 private Boolean isInit = false; + // 服务创建时调用的方法 @Override public void onCreate() { super.onCreate(); - } + // 服务销毁时调用的方法,用于注销RxBus注册以及设置初始化标记为true @Override public void onDestroy() { super.onDestroy(); @@ -60,25 +68,31 @@ public class DownloadService extends Service { isInit = true; } + // 服务启动时调用的方法,进行一些初始化操作,如获取通知管理器、注册RxBus等 @Override public int onStartCommand(Intent intent, int flags, int startId) { if (!isInit) { isInit = true; + // 获取系统的通知服务 notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + // 注册RxBus,用于接收相关事件 RxBus.get().register(this); } return super.onStartCommand(intent, flags, startId); } + // 用于绑定服务,这里返回null表示不支持绑定 @Nullable @Override public IBinder onBind(Intent intent) { return null; } + // 添加新的下载任务,将新的下载章节数据插入数据库,并根据下载状态决定是否开始下载 private void addNewTask(final List newData) { isStartDownload = true; Observable.create(new ObservableOnSubscribe() { + // 在这个方法中执行将下载章节数据插入数据库的操作 @Override public void subscribe(ObservableEmitter e) throws Exception { DbHelper.getInstance().getmDaoSession().getDownloadChapterBeanDao().insertOrReplaceInTx(newData); @@ -86,9 +100,12 @@ public class DownloadService extends Service { e.onComplete(); } }) + // 指定在主线程观察结果 .observeOn(AndroidSchedulers.mainThread()) + // 指定在IO线程执行插入数据库操作 .subscribeOn(Schedulers.io()) .subscribe(new SimpleObserver() { + // 插入成功后,如果当前没有正在下载,则调用toDownload方法开始下载 @Override public void onNext(Boolean value) { if (!isDownloading) { @@ -103,30 +120,38 @@ public class DownloadService extends Service { }); } + // 标记是否正在下载 private Boolean isDownloading = false; + // 下载失败时的重试次数 public static final int reTryTimes = 1; + // 开始下载的主要逻辑方法,查找待下载的章节并进行下载操作 private void toDownload() { isDownloading = true; if (isStartDownload) { Observable.create(new ObservableOnSubscribe() { @Override public void subscribe(ObservableEmitter e) throws Exception { + // 获取书架上的书籍列表,按最后更新日期降序排列 List bookShelfBeanList = DbHelper.getInstance().getmDaoSession().getBookShelfBeanDao().queryBuilder().orderDesc(BookShelfBeanDao.Properties.FinalDate).list(); - if (bookShelfBeanList != null && bookShelfBeanList.size() > 0) { + if (bookShelfBeanList!= null && bookShelfBeanList.size() > 0) { for (BookShelfBean bookItem : bookShelfBeanList) { + // 排除本地标签的书籍(可能表示已经下载好的本地书籍) if (!bookItem.getTag().equals(BookShelfBean.LOCAL_TAG)) { + // 查询该书籍下待下载的章节列表,按章节索引升序排列,取第一个章节(即下一个要下载的章节) List downloadChapterList = DbHelper.getInstance().getmDaoSession().getDownloadChapterBeanDao().queryBuilder().where(DownloadChapterBeanDao.Properties.NoteUrl.eq(bookItem.getNoteUrl())).orderAsc(DownloadChapterBeanDao.Properties.DurChapterIndex).limit(1).list(); - if (downloadChapterList != null && downloadChapterList.size() > 0) { + if (downloadChapterList!= null && downloadChapterList.size() > 0) { e.onNext(downloadChapterList.get(0)); e.onComplete(); return; } } } + // 如果没有待下载章节,删除所有下载章节记录 DbHelper.getInstance().getmDaoSession().getDownloadChapterBeanDao().deleteAll(); e.onNext(new DownloadChapterBean()); } else { + // 如果书架列表为空,同样删除所有下载章节记录 DbHelper.getInstance().getmDaoSession().getDownloadChapterBeanDao().deleteAll(); e.onNext(new DownloadChapterBean()); } @@ -138,12 +163,14 @@ public class DownloadService extends Service { .subscribe(new SimpleObserver() { @Override public void onNext(DownloadChapterBean value) { - if (value.getNoteUrl() != null && value.getNoteUrl().length() > 0) { + if (value.getNoteUrl()!= null && value.getNoteUrl().length() > 0) { + // 如果章节有有效的URL,开始下载该章节 downloading(value, 0); } else { Observable.create(new ObservableOnSubscribe() { @Override public void subscribe(ObservableEmitter e) throws Exception { + // 如果章节URL为空,删除所有下载章节记录 DbHelper.getInstance().getmDaoSession().getDownloadChapterBeanDao().deleteAll(); e.onNext(new Object()); e.onComplete(); @@ -178,14 +205,17 @@ public class DownloadService extends Service { } } + // 具体下载章节的逻辑方法,处理下载过程中的重试、保存数据等操作 private void downloading(final DownloadChapterBean data, final int durTime) { if (durTime < reTryTimes && isStartDownload) { + // 发送下载进度相关的事件,并显示通知 isProgress(data); Observable.create(new ObservableOnSubscribe() { @Override public void subscribe(ObservableEmitter e) throws Exception { + // 查询数据库中是否已经存在该章节的内容 List result = DbHelper.getInstance().getmDaoSession().getBookContentBeanDao().queryBuilder().where(BookContentBeanDao.Properties.DurChapterUrl.eq(data.getDurChapterUrl())).list(); - if (result != null && result.size() > 0) { + if (result!= null && result.size() > 0) { e.onNext(result.get(0)); } else { e.onNext(new BookContentBean()); @@ -196,6 +226,7 @@ public class DownloadService extends Service { @Override public ObservableSource apply(final BookContentBean bookContentBean) throws Exception { if (bookContentBean.getDurChapterUrl() == null || bookContentBean.getDurChapterUrl().length() <= 0) { + // 如果章节内容不存在,通过WebBookModelImpl获取章节内容,然后进行相关数据库操作(插入内容、更新章节列表等) return WebBookModelImpl.getInstance().getBookContent(data.getDurChapterUrl(), data.getDurChapterIndex(), data.getTag()).map(new Function() { @Override public BookContentBean apply(BookContentBean bookContentBean) throws Exception { @@ -208,6 +239,7 @@ public class DownloadService extends Service { } }); } else { + // 如果章节内容已经存在,直接删除下载章节记录并返回该章节内容 return Observable.create(new ObservableOnSubscribe() { @Override public void subscribe(ObservableEmitter e) throws Exception { @@ -224,18 +256,18 @@ public class DownloadService extends Service { .subscribe(new SimpleObserver() { @Override public void onNext(BookContentBean value) { - if(isStartDownload){ + if (isStartDownload) { new Handler().postDelayed(new Runnable() { @Override public void run() { - if(isStartDownload){ + if (isStartDownload) { toDownload(); - }else{ + } else { isPause(); } } - },800); - }else{ + }, 800); + } else { isPause(); } } @@ -252,6 +284,7 @@ public class DownloadService extends Service { Observable.create(new ObservableOnSubscribe() { @Override public void subscribe(ObservableEmitter e) throws Exception { + // 如果重试次数超过限制或者下载失败,删除该下载章节记录 DbHelper.getInstance().getmDaoSession().getDownloadChapterBeanDao().delete(data); e.onNext(true); e.onComplete(); @@ -262,18 +295,18 @@ public class DownloadService extends Service { .subscribe(new SimpleObserver() { @Override public void onNext(Boolean value) { - if(isStartDownload){ + if (isStartDownload) { new Handler().postDelayed(new Runnable() { @Override public void run() { - if(isStartDownload){ + if (isStartDownload) { toDownload(); - }else{ + } else { isPause(); } } - },800); - }else{ + }, 800); + } else { isPause(); } } @@ -281,7 +314,7 @@ public class DownloadService extends Service { @Override public void onError(Throwable e) { e.printStackTrace(); - if(!isStartDownload) + if (!isStartDownload) isPause(); } }); @@ -290,16 +323,19 @@ public class DownloadService extends Service { } } + // 对外提供的启动下载的方法,设置下载开始标记并调用toDownload方法 public void startDownload() { isStartDownload = true; toDownload(); } + // 对外提供的暂停下载的方法,设置下载暂停标记并取消所有通知 public void pauseDownload() { isStartDownload = false; notifyManager.cancelAll(); } + // 对外提供的取消下载的方法,先删除所有下载章节记录,然后暂停下载 public void cancelDownload() { Observable.create(new ObservableOnSubscribe() { @Override @@ -334,17 +370,18 @@ public class DownloadService extends Service { }); } + // 处理下载暂停相关逻辑,判断是否还有待下载章节,根据情况发送相应的RxBus事件 private void isPause() { isDownloading = false; Observable.create(new ObservableOnSubscribe() { @Override public void subscribe(ObservableEmitter e) throws Exception { List bookShelfBeanList = DbHelper.getInstance().getmDaoSession().getBookShelfBeanDao().queryBuilder().orderDesc(BookShelfBeanDao.Properties.FinalDate).list(); - if (bookShelfBeanList != null && bookShelfBeanList.size() > 0) { + if (bookShelfBeanList!= null && bookShelfBeanList.size() > 0) { for (BookShelfBean bookItem : bookShelfBeanList) { if (!bookItem.getTag().equals(BookShelfBean.LOCAL_TAG)) { List downloadChapterList = DbHelper.getInstance().getmDaoSession().getDownloadChapterBeanDao().queryBuilder().where(DownloadChapterBeanDao.Properties.NoteUrl.eq(bookItem.getNoteUrl())).orderAsc(DownloadChapterBeanDao.Properties.DurChapterIndex).limit(1).list(); - if (downloadChapterList != null && downloadChapterList.size() > 0) { + if (downloadChapterList!= null && downloadChapterList.size() > 0) { e.onNext(downloadChapterList.get(0)); e.onComplete(); return; @@ -364,9 +401,11 @@ public class DownloadService extends Service { .subscribe(new SimpleObserver() { @Override public void onNext(DownloadChapterBean value) { - if (value.getNoteUrl() != null && value.getNoteUrl().length() > 0){ + if (value.getNoteUrl()!= null && value.getNoteUrl().length() > 0) { + // 如果还有待下载章节,发送暂停下载的监听事件 RxBus.get().post(RxBusTag.PAUSE_DOWNLOAD_LISTENER, new Object()); - }else{ + } else { + // 如果没有待下载章节,发送下载完成的监听事件 RxBus.get().post(RxBusTag.FINISH_DOWNLOAD_LISTENER, new Object()); } } @@ -377,27 +416,43 @@ public class DownloadService extends Service { } }); } - + + // 方法作用:处理下载进度相关操作,发送下载进度相关信息到RxBus,并创建和发送通知展示下载进度情况 +// 参数:downloadChapterBean表示下载章节相关的数据对象,包含了如书籍名称、当前章节名称等信息 private void isProgress(DownloadChapterBean downloadChapterBean) { + // 通过RxBus发送下载进度监听器相关的事件,传递下载章节数据对象,以便其他地方能接收到并处理进度信息 RxBus.get().post(RxBusTag.PROGRESS_DOWNLOAD_LISTENER, downloadChapterBean); + // 创建一个意图,用于启动主活动(MainActivity),这里的上下文是当前类所在的上下文环境 Intent mainIntent = new Intent(this, MainActivity.class); + // 根据创建的意图创建一个PendingIntent对象,用于后续设置到通知中,使得点击通知可以启动对应的活动 + // 这里的请求码设置为0,并且设置当有相同请求码的PendingIntent更新时,更新当前的PendingIntent PendingIntent mainPendingIntent = PendingIntent.getActivity(this, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT); - //创建 Notification.Builder 对象 + + // 创建 Notification.Builder 对象,用于构建通知 NotificationCompat.Builder builder = new NotificationCompat.Builder(this) + // 设置通知的小图标,这里使用的是资源文件中定义的ic_launcher图标 .setSmallIcon(R.mipmap.ic_launcher) - //点击通知后自动清除 + // 设置点击通知后自动清除该通知 .setAutoCancel(true) - .setContentTitle("正在下载:"+downloadChapterBean.getBookName()) - .setContentText(downloadChapterBean.getDurChapterName()==null?" ":downloadChapterBean.getDurChapterName()) + // 设置通知的标题,展示正在下载的书籍名称 + .setContentTitle("正在下载:" + downloadChapterBean.getBookName()) + // 根据当前章节名称是否为空来设置通知的内容文本,如果为空则设置为空格,否则设置为章节名称 + .setContentText(downloadChapterBean.getDurChapterName() == null? " " : downloadChapterBean.getDurChapterName()) + // 将前面创建的PendingIntent设置到通知中,使得点击通知能启动对应的活动 .setContentIntent(mainPendingIntent); - //发送通知 + + // 使用通知管理器发送通知,notifiId应该是预先定义好的通知的唯一标识,用于区分不同的通知 notifyManager.notify(notifiId, builder.build()); } + // 方法作用:完成下载相关的后续操作,发送下载完成的事件到RxBus,取消所有通知,并弹出提示告知用户全部离线章节下载完成 private void finishDownload() { + // 通过RxBus发送下载完成监听器相关的事件,传递一个空的Object对象,作为完成下载的一种通知机制,方便其他地方监听并处理完成下载的情况 RxBus.get().post(RxBusTag.FINISH_DOWNLOAD_LISTENER, new Object()); + // 取消所有已发送的通知 notifyManager.cancelAll(); + // 在主线程中执行以下代码块,用于弹出一个短暂显示的Toast提示信息,告知用户全部离线章节下载完成 new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { @@ -406,6 +461,8 @@ public class DownloadService extends Service { }); } + // 方法作用:响应RxBus中PAUSE_DOWNLOAD事件,调用pauseDownload方法(此处假设pauseDownload方法在别处定义,用于暂停下载任务相关操作) +// 该方法被标注为订阅RxBus中特定标签的事件,并且在主线程中执行 @Subscribe( thread = EventThread.MAIN_THREAD, tags = { @@ -416,6 +473,8 @@ public class DownloadService extends Service { pauseDownload(); } + // 方法作用:响应RxBus中START_DOWNLOAD事件,调用startDownload方法(此处假设startDownload方法在别处定义,用于启动下载任务相关操作) +// 该方法被标注为订阅RxBus中特定标签的事件,并且在主线程中执行 @Subscribe( thread = EventThread.MAIN_THREAD, tags = { @@ -426,6 +485,8 @@ public class DownloadService extends Service { startDownload(); } + // 方法作用:响应RxBus中CANCEL_DOWNLOAD事件,调用cancelDownload方法(此处假设cancelDownload方法在别处定义,用于取消下载任务相关操作) +// 该方法被标注为订阅RxBus中特定标签的事件,并且在主线程中执行 @Subscribe( thread = EventThread.MAIN_THREAD, tags = { @@ -436,6 +497,9 @@ public class DownloadService extends Service { cancelDownload(); } + // 方法作用:响应RxBus中ADD_DOWNLOAD_TASK事件,调用addNewTask方法(此处假设addNewTask方法在别处定义,用于添加新的下载任务相关操作) +// 该方法接收一个DownloadChapterListBean类型的对象newData,从其中获取具体的数据(假设是下载任务列表数据)传递给addNewTask方法进行处理 +// 该方法被标注为订阅RxBus中特定标签的事件,并且在主线程中执行 @Subscribe( thread = EventThread.MAIN_THREAD, tags = { @@ -444,5 +508,4 @@ public class DownloadService extends Service { ) public void addTask(DownloadChapterListBean newData) { addNewTask(newData.getData()); - } -} \ No newline at end of file + } \ No newline at end of file