/**
* Copyright 2016 JustWayward Team
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.justwayward.reader.service;
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.justwayward.reader.R;
import com.justwayward.reader.ReaderApplication;
import com.justwayward.reader.api.BookApi;
import com.justwayward.reader.api.support.Logger;
import com.justwayward.reader.api.support.LoggingInterceptor;
import com.justwayward.reader.bean.BookMixAToc;
import com.justwayward.reader.bean.ChapterRead;
import com.justwayward.reader.bean.support.DownloadMessage;
import com.justwayward.reader.bean.support.DownloadProgress;
import com.justwayward.reader.bean.support.DownloadQueue;
import com.justwayward.reader.manager.CacheManager;
import com.justwayward.reader.utils.AppUtils;
import com.justwayward.reader.utils.LogUtils;
import com.justwayward.reader.utils.NetworkUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.List;
import rx.Observer;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;
/**
* @author yuyh.
* @date 16/8/13.
*/
public class DownloadBookService extends Service {
public static List<DownloadQueue> downloadQueues = new ArrayList<>();
public BookApi bookApi;
protected CompositeSubscription mCompositeSubscription;
public boolean isBusy = false; // 当前是否有下载任务在进行
public static boolean canceled = false;
@Override
public void onCreate() {
super.onCreate();
EventBus.getDefault().register(this);
LoggingInterceptor logging = new LoggingInterceptor(new Logger());
logging.setLevel(LoggingInterceptor.Level.BODY);
bookApi = ReaderApplication.getsInstance().getAppComponent().getReaderApi();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
unSubscribe();
EventBus.getDefault().unregister(this);
}
public static void post(DownloadQueue downloadQueue) {
EventBus.getDefault().post(downloadQueue);
}
public void post(DownloadProgress progress) {
EventBus.getDefault().post(progress);
}
private void post(DownloadMessage message) {
EventBus.getDefault().post(message);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public synchronized void addToDownloadQueue(DownloadQueue queue) {
if (!TextUtils.isEmpty(queue.bookId)) {
boolean exists = false;
// 判断当前书籍缓存任务是否存在
for (int i = 0; i < downloadQueues.size(); i++) {
if (downloadQueues.get(i).bookId.equals(queue.bookId)) {
LogUtils.e("addToDownloadQueue:exists");
exists = true;
break;
}
}
if (exists) {
post(new DownloadMessage(queue.bookId, "当前缓存任务已存在", false));
return;
}
// 添加到下载队列
downloadQueues.add(queue);
LogUtils.e("addToDownloadQueue:" + queue.bookId);
post(new DownloadMessage(queue.bookId, "成功加入缓存队列", false));
}
// 从队列顺序取出第一条下载
if (downloadQueues.size() > 0 && !isBusy) {
isBusy = true;
downloadBook(downloadQueues.get(0));
}
}
public synchronized void downloadBook(final DownloadQueue downloadQueue) {
AsyncTask<Integer, Integer, Integer> downloadTask = new AsyncTask<Integer, Integer, Integer>() {
List<BookMixAToc.mixToc.Chapters> list = downloadQueue.list;
String bookId = downloadQueue.bookId;
int start = downloadQueue.start; // 起始章节
int end = downloadQueue.end; // 结束章节
@Override
protected Integer doInBackground(Integer... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
int failureCount = 0;
for (int i = start; i <= end && i <= list.size(); i++) {
if (canceled) {
break;
}
// 网络异常,取消下载
if (!NetworkUtils.isAvailable(AppUtils.getAppContext())) {
downloadQueue.isCancel = true;
post(new DownloadMessage(bookId, getString(R.string.book_read_download_error), true));
failureCount = -1;
break;
}
if (!downloadQueue.isFinish && !downloadQueue.isCancel) {
// 章节文件不存在,则下载,否则跳过
if (CacheManager.getInstance().getChapterFile(bookId, i) == null) {
BookMixAToc.mixToc.Chapters chapters = list.get(i - 1);
String url = chapters.link;
int ret = download(url, bookId, chapters.title, i, list.size());
if (ret != 1) {
failureCount++;
}
} else {
post(new DownloadProgress(bookId, String.format(
getString(R.string.book_read_alreday_download), list.get(i - 1).title, i, list.size()),
true));
}
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
return failureCount;
}
@Override
protected void onPostExecute(Integer failureCount) {
super.onPostExecute(failureCount);
downloadQueue.isFinish = true;
if (failureCount > -1) {
// 完成通知
post(new DownloadMessage(bookId,
String.format(getString(R.string.book_read_download_complete), failureCount), true));
}
// 下载完成,从队列里移除
downloadQueues.remove(downloadQueue);
// 释放 空闲状态
isBusy = false;
if (!canceled) {
// post一个空事件,通知继续执行下一个任务
post(new DownloadQueue());
} else {
downloadQueues.clear();
}
canceled = false;
LogUtils.i(bookId + "缓存完成,失败" + failureCount + "章");
}
};
downloadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private int download(String url, final String bookId, final String title, final int chapter, final int chapterSize) {
final int[] result = {-1};
Subscription subscription = bookApi.getChapterRead(url)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ChapterRead>() {
@Override
public void onNext(ChapterRead data) {
if (data.chapter != null) {
post(new DownloadProgress(bookId, String.format(
getString(R.string.book_read_download_progress), title, chapter, chapterSize),
true));
CacheManager.getInstance().saveChapterFile(bookId, chapter, data.chapter);
result[0] = 1;
} else {
result[0] = 0;
}
}
@Override
public void onCompleted() {
result[0] = 1;
}
@Override
public void onError(Throwable e) {
result[0] = 0;
}
});
addSubscrebe(subscription);
while (result[0] == -1) {
try {
Thread.sleep(350);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return result[0];
}
public static void cancel() {
canceled = true;
}
protected void unSubscribe() {
if (mCompositeSubscription != null) {
mCompositeSubscription.unsubscribe();
}
}
protected void addSubscrebe(Subscription subscription) {
if (mCompositeSubscription == null) {
mCompositeSubscription = new CompositeSubscription();
}
mCompositeSubscription.add(subscription);
}
}