1. 完善缓存下载服务

2.新服务端api调整
This commit is contained in:
mwang 2019-04-09 22:32:02 +08:00
parent ed86212f9e
commit 4ef4861c70
21 changed files with 618 additions and 224 deletions

View File

@ -122,6 +122,10 @@
android:label="@string/app_name"
android:theme="@style/ToolBarTheme.NoActionBar">
</activity>
<service android:name="com.novelbook.android.service.ServiceDownload" android:exported="false"/>
<service android:name="com.novelbook.android.service.MyIntentService" android:exported="false"/>
<service android:name="com.novelbook.android.service.ChapterDownloadSvrc" android:exported="false"/>
</application>
</manifest>

View File

@ -2,12 +2,13 @@
<litepal>
<dbname value="book" ></dbname>
<version value="3" ></version>
<version value="1" ></version>
<list>
<mapping class="com.novelbook.android.db.Chapter"></mapping>
<mapping class="com.novelbook.android.db.Novel"></mapping>
<mapping class="com.novelbook.android.db.BookMarks"></mapping>
<mapping class="com.novelbook.android.db.SiteRule"></mapping>
<mapping class="com.novelbook.android.db.DownloadTask"></mapping>
</list>
</litepal>

View File

@ -121,7 +121,7 @@ public abstract class Activity_base extends AppCompatActivity {
bk.setAuthor("金庸");
bk.setName("射雕英雄传" +(char)i);
bk.setNovelType("武侠");
bk.setDescription("南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事");
bk.setDesc("南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事");
mDatas.add(bk);
}
return mDatas;

View File

@ -111,7 +111,7 @@ public class Activity_createShudan extends Activity_base {
bk.setAuthor("金庸" +i);
bk.setName("射雕" +(char)i);
bk.setNovelType("cate" +i);
bk.setDescription(" 南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事");
bk.setDesc(" 南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事");
mData .add(bk);
}
@ -188,7 +188,7 @@ public class Activity_createShudan extends Activity_base {
holder.tvTitle.setText(mDatas.get(position).getName());
holder.tvAuthor.setText(mDatas.get(position).getAuthor());
holder.tvCate.setText(mDatas.get(position).getNovelType());
holder.tvDesc.setText(mDatas.get(position).getDescription());
holder.tvDesc.setText(mDatas.get(position).getDesc());
// 如果设置了回调则设置点击事件

View File

@ -2,9 +2,11 @@ package com.novelbook.android;
import android.Manifest;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
@ -34,6 +36,8 @@ import com.novelbook.android.netutils.HttpMethods;
import com.novelbook.android.netutils.OnSuccessAndFaultListener;
import com.novelbook.android.netutils.OnSuccessAndFaultSub;
import com.novelbook.android.service.ChapterDownloadSvrc;
import com.novelbook.android.service.MyIntentService;
import com.novelbook.android.service.ServiceDownload;
import com.novelbook.android.utils.BookUtil;
import com.novelbook.android.utils.GsonUtil;
@ -66,16 +70,17 @@ import static com.novelbook.android.FileActivity.EXTERNAL_STORAGE_REQ_CODE;
public class BookActivity extends Activity_base {
private PageFactory pageFactory;
String novelId="f2619820112625133c14dcb170f5e092";
String muluUrl="https://www.qu.la/book/390/";
int novelId = 31590;
// String muluUrl = "https://www.qu.la/book/390/";
private Novel mNovel;
private Chapter mChapter;
static String TAG = BookActivity.class.getSimpleName();
BookListAdapter mAdapter;
// private BookListAdapter mAdapter;
private List<Novel> mData;;
private List<Novel> mData;
;
private Gson gson = new Gson();
private List<Chapter> mChapters = new ArrayList<>();
private List<Chapter> mChapters = new ArrayList<>();
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.rvBooklist)
@ -96,10 +101,18 @@ public class BookActivity extends Activity_base {
TextView txtDesc2;
@BindView(R.id.txtLatestCate)
TextView txtLatestCate;
@BindView(R.id.btnCacheBook)
Button btnCach;
Intent serviceIntent ;
public Intent getSvrIntent(){
if(serviceIntent ==null){
serviceIntent= new Intent(this, ServiceDownload.class);
}
return serviceIntent;
}
@Override
public int getLayoutRes() {
@ -111,8 +124,8 @@ public class BookActivity extends Activity_base {
initialBookList();
}
@Override
protected void setupToolbar(){
@Override
protected void setupToolbar() {
super.setupToolbar();
toolbar.inflateMenu(R.menu.menu_book);//设置右上角的填充菜单
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@ -130,70 +143,77 @@ public class BookActivity extends Activity_base {
@Override
protected void setTitle() {
// String title = getIntent().getStringExtra("BOOKNAME");
// this.setTitle(title);
// String title = getIntent().getStringExtra("BOOKNAME");
// this.setTitle(title);
int bookId = getIntent().getIntExtra("bookId",0);
// this.setTitle("bookName");
int bookId = getIntent().getIntExtra("bookId", 0);
// this.setTitle("bookName");
}
@Override
protected void initData() {
initiDownloadReceiver();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkPermission(BookActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE, EXTERNAL_STORAGE_REQ_CODE,"添加图书需要此权限,请允许");
checkPermission(BookActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE, EXTERNAL_STORAGE_REQ_CODE, "添加图书需要此权限,请允许");
}
pageFactory = PageFactory.getInstance();
setBookInfo();//set title ,data from novel list
if(mNovel==null) {
if (mNovel == null) {
getBookInfo();
}
mData =getFakeData(5);
mData = getFakeData(5);
mAdapter = getBookListAdapter(mData);
}
private void setBookInfo() {
}
private MyImageLoader loader = new MyImageLoader();
public void setBookDetailInfo( ){
public void setBookDetailInfo() {
setShelfButtonText();
this.setTitle(mNovel.getName());//why not apply
this.txtAuth.setText(mNovel.getAuthor());
this.txtCategory.setText(mNovel.getNovelType());
this.txtDesc.setText(mNovel.getDescription());
this.txtDesc.setText(mNovel.getDesc ());
this.txtTitle.setText(mNovel.getName());
this.txtDesc2.setText(mNovel.getDescription());
this.txtLatestCate.setText(mNovel.getLastestChapterName());
if(mNovel.getLastUpateTime()>0){
this.txtLatestCate.setText( new Date(mNovel.getLastUpateTime()).toString() +"\n"+txtLatestCate.getText());
this.txtDesc2.setText(mNovel.getDesc ());
this.txtLatestCate.setText(mNovel.getChapterName());
if (mNovel.getLastUpateTime() > 0) {
this.txtLatestCate.setText(new Date(mNovel.getLastUpateTime()).toString() + "\n" + txtLatestCate.getText());
}
if(!TextUtils.isEmpty(mNovel.getCover())) {
loader.displayImage(BookActivity.this, mNovel.getCover(), imageView);
if (!TextUtils.isEmpty(mNovel.getCover())) {
String cover =mNovel.getCover();
if(!TextUtils.isEmpty(cover) ){
if(cover.startsWith("//")){
cover ="http:"+cover;
}
}
loader.displayImage(BookActivity.this, cover, imageView);
}
}
void setShelfButtonText(){
String title = mNovel.isOnShelf()?"移除书架":"加入书架";
void setShelfButtonText() {
String title = mNovel.isOnShelf() ? "移除书架" : "加入书架";
btnShelf.setText(title);
}
@OnClick({R.id.btnRead,R.id.btnCacheBook,R.id.btnShelf})
void submitButton(View view){
@OnClick({R.id.btnRead, R.id.btnCacheBook, R.id.btnShelf})
void submitButton(View view) {
switch (view.getId()) {
case R.id.btnRead:
readBook();
//testBook();
// openBook(new Novel() );
// openBook(new Novel() );
break;
case R.id.btnCacheBook:
cacheBook();
@ -205,7 +225,7 @@ public class BookActivity extends Activity_base {
}
}
}
private void shelfBook() {
mNovel.setOnShelf(!mNovel.isOnShelf());
@ -213,32 +233,34 @@ public class BookActivity extends Activity_base {
setShelfButtonText();
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
int wt = msg.what;
if (msg.what == 1 ) {
if (msg.what == 1) {
setBookDetailInfo();
}else if(msg.what==2) //准备数据启动service
} else if (msg.what == 2) //准备数据启动service
{
hideProgress();
Toast.makeText(BookActivity.this,"已加入下载队列1",Toast.LENGTH_LONG).show();
}else if(msg.what==3){
Toast.makeText(BookActivity.this,"获取目录信息失败,下载失败",Toast.LENGTH_LONG).show();
Toast.makeText(BookActivity.this, "已加入下载队列1", Toast.LENGTH_LONG).show();
} else if (msg.what == 3) {
Toast.makeText(BookActivity.this, "获取目录信息失败,下载失败", Toast.LENGTH_LONG).show();
}
}
};
private void readBook() {
if(mNovel ==null){
Toast.makeText(this,"网络错误",Toast.LENGTH_LONG);
if (mNovel == null) {
Toast.makeText(this, "网络错误", Toast.LENGTH_LONG);
return;
}
ReadActivity.openBook(mNovel , BookActivity.this);
ReadActivity.openBook(mNovel, BookActivity.this);
}
@ -248,23 +270,75 @@ public class BookActivity extends Activity_base {
}
boolean test=false;
private void cacheBook() {
if( LitePal.where("novelId = ?",mNovel.getId()+"").count("DownloadTask") >0){
Toast.makeText(this,"已经在下载队列",Toast.LENGTH_LONG).show();
Intent serviceIntent = new Intent(BookActivity.this, ServiceDownload.class);
startService(serviceIntent);
if(test)
{
return;
}
String url[] = {
"https://img-blog.csdn.net/20160903083245762",
"https://img-blog.csdn.net/20160903083252184",
"https://img-blog.csdn.net/20160903083257871",
"https://img-blog.csdn.net/20160903083257871",
"https://img-blog.csdn.net/20160903083311972",
"https://img-blog.csdn.net/20160903083319668",
"https://img-blog.csdn.net/20160903083326871"
};
Intent intent = new Intent(this, MyIntentService.class);
for (int i=0;i<7;i++) {//循环启动任务
intent.putExtra(MyIntentService.DOWNLOAD_URL,url[i]);
intent.putExtra(MyIntentService.INDEX_FLAG,i);
startService(intent);
}
intent = getSvrIntent();//new Intent(this, ServiceDownload.class);;;
for(int i=0;i<5;i++)
{
intent.putExtra("taskId",i);
startService( intent);
}
// intent = new Intent(this, ChapterDownloadSvrc.class);;;
// for(int i=0;i<3;i++)
{
// intent.putExtra("taskId",i);
// startService( intent);
}
return;
}
// if (LitePal.where("novelId = ?", mNovel.getId() + "").count("DownloadTask") > 0) {
List<DownloadTask> dts = LitePal.where("novelId = ?", mNovel.getId() + "").limit(1).find(DownloadTask.class);
if (dts.size() > 0) {
if (dts.get(0).getStatus() == 1) {
Toast.makeText(this, String.format("亲,小说《%s》已经缓存完成了", mNovel.getName()), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, String.format("亲,小说《%s》已经在缓存队列了请耐心等待", mNovel.getName()), Toast.LENGTH_LONG).show();
startDownloadService(dts.get(0).getId());
// startService( getSvrIntent());
}
return;
}
// }
new Thread() {
@Override
public void run() {
int slepttime =0;
while (slepttime < 100 && pageFactory.getChapters().size() ==0){
int slepttime = 0;
while (slepttime < 100 && pageFactory.getChapters().size() == 0) {
try {
sleep(50);
slepttime++;
@ -272,12 +346,11 @@ public class BookActivity extends Activity_base {
e.printStackTrace();
}
}
if(pageFactory.getChapters().size() ==0){
if (pageFactory.getChapters().size() == 0) {
handler.sendEmptyMessage(3);
}
else{
} else {
DownloadTask dt = new DownloadTask();
dt.setDomain(mNovel.getDomain());
dt.setFinishedChpats(0);
@ -285,38 +358,43 @@ public class BookActivity extends Activity_base {
dt.setStatus(0);
dt.setTotalChapts(mNovel.getTotalChapts());
dt.save();
// LitePal.deleteAll("chapter","novelId=?",mNovel.getId()+"");
for(Chapter chapter: pageFactory.getChapters()){
// LitePal.deleteAll("chapter","novelId=?",mNovel.getId()+"");
for (Chapter chapter : pageFactory.getChapters()) {
chapter.setNovelId(mNovel.getId());
chapter.save();
}
Intent serviceIntent = new Intent(BookActivity.this, ServiceDownload.class);
serviceIntent.putExtra("taskId",dt.getId());
startService(serviceIntent);
startDownloadService(dt.getId());
handler.sendEmptyMessage(2);
}
// Toast.makeText(BookActivity.this,"已加入下载队列2",Toast.LENGTH_LONG).show();
// Toast.makeText(BookActivity.this,"已加入下载队列2",Toast.LENGTH_LONG).show();
}
}.start();
}.start();
showProgress(false,"正在加入到队列,请等待");
showProgress(false, "正在加入到队列,请等待");
}
void openBook(Novel book ) {
private void startDownloadService(int taskId) {
Intent serviceIntent = getSvrIntent();
serviceIntent.putExtra("taskId",taskId);
startService(serviceIntent);
}
void openBook(Novel book) {
final String path = book.getNovelPath();
if(null ==path) {
List<Novel> bookLists = LitePal.findAll(Novel.class);
if(bookLists.size()>0) {
openBook(bookLists.get(0) );
if (null == path) {
List<Novel> bookLists = LitePal.findAll(Novel.class);
if (bookLists.size() > 0) {
openBook(bookLists.get(0));
}
return;
}
File file = new File(path);
if (!file.exists()){
if (!file.exists()) {
//to get book content txt from web
new AlertDialog.Builder(this)
@ -331,60 +409,57 @@ public class BookActivity extends Activity_base {
}).setCancelable(true).show();
return;
}
// ReadActivity.openBook(book ,null,this);
// ReadActivity.openBook(book ,null,this);
}
void getBookInfo() {
boolean isLocalDbExist = LitePal.isExist(Novel.class, "novelId=?", novelId+"");
void getBookInfo(){
boolean isLocalDbExist = LitePal.isExist(Novel.class,"novelId=?", novelId);
BookSubscribe.getNovel(novelId,new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
BookSubscribe.getNovel(novelId, new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
@Override
public void onSuccess(String result) {
//成功
Novel nv ;
nv = gson.fromJson(result,Novel.class);
// nv = GsonUtil.getNovel(result);
Novel nv;
nv = gson.fromJson(result, Novel.class);
// nv = GsonUtil.getNovel(result);
if(!isLocalDbExist){
// nv.saveAsync();
nv.save ();
if (!isLocalDbExist) {
// nv.saveAsync();
nv.save();
}else{
} else {
nv.updateAll("novelId=?",novelId);
nv.updateAll("novelId=?", novelId+"");
}
mNovel = Novel.getNovelBySvrId(novelId);
if(null != mNovel) {
if (null != mNovel) {
handler.sendEmptyMessage(1);
}
pageFactory.prepareBook(mNovel );
pageFactory.prepareBook(mNovel);
// Toast.makeText(BookActivity.this,"Novel 请求成功:"+result,Toast.LENGTH_SHORT).show();
// Toast.makeText(BookActivity.this,"Novel 请求成功:"+result,Toast.LENGTH_SHORT).show();
}
@Override
public void onFault(String errorMsg) {
//失败
Toast.makeText(BookActivity.this,"Novel 请求失败:"+errorMsg,Toast.LENGTH_SHORT).show();
Toast.makeText(BookActivity.this, "Novel 请求失败:" + errorMsg, Toast.LENGTH_SHORT).show();
mNovel = Novel.getNovelBySvrId(novelId);
if(null != mNovel) {
if (null != mNovel) {
handler.sendEmptyMessage(1);
pageFactory.prepareBook(mNovel );
pageFactory.prepareBook(mNovel);
}
}
},BookActivity.this));
}, BookActivity.this));
}
/*
@ -461,25 +536,62 @@ void onResponseProcess( String content ,String url){
rvBooklist.setLayoutManager(new LinearLayoutManager(this));
rvBooklist.setAdapter(mAdapter);
}
@Override
protected void onResume() {
super.onResume();
// View v =findViewById(R.id.head_img);
// v.measure(0,0);
// BlurKit.getInstance().blur(v, 20);
// BlurKit.getInstance().fastBlur(v,20, 0.3f);
registerReceiver(receiver,filter);
// View v =findViewById(R.id.head_img);
// v.measure(0,0);
// BlurKit.getInstance().blur(v, 20);
// BlurKit.getInstance().fastBlur(v,20, 0.3f);
}
@Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
@Override
protected void onStart() {
super.onStart();
// blurLayout.startBlur();
// blurLayout.lockView();
// blurLayout.startBlur();
// blurLayout.lockView();
}
@Override
protected void onStop() {
super.onStop();
// blurLayout.pauseBlur();
super.onStop();
// blurLayout.pauseBlur();
}
private IntentFilter filter;
DownloadProcessReceiver receiver;
void initiDownloadReceiver(){
filter = new IntentFilter("ServiceDownload.ChapterContent.finished");
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new DownloadProcessReceiver();
}
class DownloadProcessReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
int novelId =0;
int progress=0;
if( intent.hasExtra("novelId")){
novelId = intent.getIntExtra("novelId",0);
}
if( intent.hasExtra("progress")){
progress = intent.getIntExtra("progress",0);
}
if(novelId == mNovel.getId()){
btnCach.setText(progress +"/" +pageFactory.getChapters().size());
}
}
}
}

View File

@ -129,7 +129,7 @@ public abstract class BasicFragment extends Fragment {
bk.setAuthor("金庸");
bk.setName("射雕英雄传" +(char)i);
bk.setNovelType("武侠");
bk.setDescription("南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事");
bk.setDesc("南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事南宋时期的武林故事");
mDatas.add(bk);
}
return mDatas;
@ -142,7 +142,7 @@ public abstract class BasicFragment extends Fragment {
}
void getBookInfo(Novel novel){
String novelId = novel.getNovelId();
int novelId = novel.getNovelId();
long id = novel.getId();

View File

@ -402,7 +402,7 @@ public class Fragment_Shelf extends BasicFragment {
holder.tvTitle.setText(mDatas.get(position).getName());
if(holder.tvAuthor!=null) holder.tvAuthor.setText(mDatas.get(position).getAuthor());
if(holder.tvCate!=null) holder.tvCate.setText(mDatas.get(position).getNovelType());
if(holder.tvDesc!=null) holder.tvDesc.setText(mDatas.get(position).getDescription());
if(holder.tvDesc!=null) holder.tvDesc.setText(mDatas.get(position).getDesc ());
if(holder.checkBox!=null) holder.checkBox.setVisibility(View.VISIBLE);
// 如果设置了回调则设置点击事件
if (mOnItemClickListener != null)

View File

@ -85,7 +85,7 @@ public class BookListAdapter extends RecyclerView.Adapter< MyViewHolder> {
holder.tvTitle.setText(mDatas.get(position).getName());
if (holder.tvAuthor != null) holder.tvAuthor.setText(mDatas.get(position).getAuthor());
if (holder.tvCate != null) holder.tvCate.setText(mDatas.get(position).getNovelType());
if (holder.tvDesc != null) holder.tvDesc.setText(mDatas.get(position).getDescription());
if (holder.tvDesc != null) holder.tvDesc.setText(mDatas.get(position).getDesc());
if (holder.imageView != null && !TextUtils.isEmpty(mDatas.get(position).getCover())) {
loader.displayImage(context,mDatas.get(position).getCover(),holder.imageView);
}

View File

@ -101,8 +101,8 @@ public class Chapter extends LitePalSupport implements Serializable {
}
public static List<Chapter> getUnCachedChapters(int noveId,String domain ){
// return LitePal.where("novelId = ? and domain = ? and chapterPath = ?" ,noveId+"",domain,"null") .find(Chapter.class);
return LitePal.where("novelId = ? and domain = ? " ,noveId+"",domain).find(Chapter.class);
return LitePal.where("novelId = ? and domain = ? and chapterPath = ?" ,noveId+"",domain,"") .find(Chapter.class);
// return LitePal.where("novelId = ? and domain = ? " ,noveId+"",domain).find(Chapter.class);
}

View File

@ -1,5 +1,6 @@
package com.novelbook.android.db;
import org.litepal.annotation.Column;
import org.litepal.crud.LitePalSupport;
import java.io.Serializable;
@ -9,7 +10,8 @@ public class DownloadTask extends LitePalSupport implements Serializable {
private int id;
private int novelId;
private String domain;
private int status;
@Column( defaultValue = "0")
private int status; //0 未完成 1 完成
private int totalChapts;
private int finishedChpats;

View File

@ -14,9 +14,10 @@ import java.util.List;
public class Novel extends LitePalSupport implements Serializable{
private int id;
@Column(unique = true, nullable = true)
private String novelId;
//@Column(unique = true, defaultValue = "0")
private int novelId;
private String name;
private String infoUrl;
private String domain;
private String muluUrl;
private String novelPath;
@ -24,15 +25,56 @@ public class Novel extends LitePalSupport implements Serializable{
private int lastReadChapt=1;
private String charset;
private String novelType;
private String novelType2;
private String smallNovelType;
private String author;
private String cover;
private String lastestChapterName;
private String description;
private String chapterName;
private String desc;
private String progress;
private long lastUpateTime;
private boolean isOnShelf; //是否入书架
private boolean isFinished; //是否完本
public String getInfoUrl() {
return infoUrl;
}
public void setInfoUrl(String infoUrl) {
this.infoUrl = infoUrl;
}
public String getSmallNovelType() {
return smallNovelType;
}
public void setSmallNovelType(String smallNovelType) {
this.smallNovelType = smallNovelType;
}
public String getChapterName() {
return chapterName;
}
public void setChapterName(String chapterName) {
this.chapterName = chapterName;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getProgress() {
return progress;
}
public void setProgress(String progress) {
this.progress = progress;
}
public int getTotalChapts() {
return totalChapts;
}
@ -41,9 +83,7 @@ public class Novel extends LitePalSupport implements Serializable{
this.totalChapts = totalChapts;
}
private int totalChapts=1000;
private int totalChapts;
public int getId() {
return id;
@ -53,11 +93,11 @@ public class Novel extends LitePalSupport implements Serializable{
this.id = id;
}
public String getNovelId() {
public int getNovelId() {
return novelId;
}
public void setNovelId(String novelId) {
public void setNovelId(int novelId) {
this.novelId = novelId;
}
@ -125,13 +165,7 @@ public class Novel extends LitePalSupport implements Serializable{
this.novelType = novelType;
}
public String getNovelType2() {
return novelType2;
}
public void setNovelType2(String novelType2) {
this.novelType2 = novelType2;
}
public String getAuthor() {
return author;
@ -149,21 +183,6 @@ public class Novel extends LitePalSupport implements Serializable{
this.cover = cover;
}
public String getLastestChapterName() {
return lastestChapterName;
}
public void setLastestChapterName(String lastestChapterName) {
this.lastestChapterName = lastestChapterName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public long getLastUpateTime() {
return lastUpateTime;
@ -190,11 +209,11 @@ public class Novel extends LitePalSupport implements Serializable{
}
public boolean isLocalBook(){
return TextUtils.isEmpty(novelId);
return novelId==0;
}
public static Novel getNovelBySvrId(String novelId){
public static Novel getNovelBySvrId(int novelId){
List<Novel> nvs = LitePal.where("novelId=?",novelId).limit(1).find(Novel.class);
List<Novel> nvs = LitePal.where("novelId=?",novelId+"").limit(1).find(Novel.class);
if(nvs.size()>0){
return nvs.get(0);
}

View File

@ -38,12 +38,12 @@ public interface HttpApi {
@GET("g")
Observable<ResponseBody> getMasterDomain();
//http://xiaoshuofenxiang.com/api/n/f2619820112625133c14dcb170f5e092.json
@GET("n/{id}.json")
Observable<ResponseBody> getNovel(@Path("id") String novelId);
@GET("n/{id}")
Observable<ResponseBody> getNovel(@Path("id") int novelId);
//http://xiaoshuofenxiang.com/api/n/f2619820112625133c14dcb170f5e092.mulu-urls.json
@GET("n/{id}.mulu-urls.json")
Observable<ResponseBody> getNovelSites(@Path("id") String novelId);
@GET("n/{id}/mulu-urls")
Observable<ResponseBody> getNovelSites(@Path("id") int novelId);
//http://xiaoshuofenxiang.com/api/s/www.qu.la.json
@GET("s/{siteDomain}.json")

View File

@ -18,11 +18,11 @@ public class BookSubscribe {
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getNovel(String novelId,DisposableObserver<ResponseBody> subscriber){
public static void getNovel(int novelId,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovel(novelId);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getNovelSites(String novelId,DisposableObserver<ResponseBody> subscriber){
public static void getNovelSites(int novelId,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovelSites(novelId);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}

View File

@ -244,7 +244,7 @@ public class HttpMethods {
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
String cacheControl = originalResponse.header("Cache-Control");
int maxAge =60*60; //一小时
int maxAge =0; //一小时
if (cacheControl == null || cacheControl.contains("no-store") || cacheControl.contains("no-cache") ||
cacheControl.contains("must-revalidate") || cacheControl.contains("max-age=0")) { //目标网站禁用cache则设置为1小时
return originalResponse.newBuilder()
@ -252,7 +252,7 @@ public class HttpMethods {
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
return originalResponse;
return originalResponse;
}
}
};

View File

@ -0,0 +1,120 @@
package com.novelbook.android.service;
import android.app.IntentService;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class MyIntentService extends IntentService {
public static final String DOWNLOAD_URL="download_url";
public static final String INDEX_FLAG="index_flag";
public static UpdateUI updateUI;
final String TAG ="testIntentService";
public static void setUpdateUI(UpdateUI updateUIInterface){
updateUI=updateUIInterface;
}
public MyIntentService(){
super("MyIntentService");
}
/**
* 实现异步任务的方法
* @param intent Activity传递过来的Intent,数据封装在intent中
*/
@Override
protected void onHandleIntent(Intent intent) {
//在子线程中进行网络请求
Bitmap bitmap=downloadUrlBitmap(intent.getStringExtra(DOWNLOAD_URL));
Message msg1 = new Message();
msg1.what = intent.getIntExtra(INDEX_FLAG,0);
msg1.obj =bitmap;
//通知主线程去更新UI
if(updateUI!=null){
updateUI.updateUI(msg1);
}
//mUIHandler.sendMessageDelayed(msg1,1000);
Log.d(TAG,"onHandleIntent");
}
//----------------------重写一下方法仅为测试------------------------------------------
@Override
public void onCreate() {
Log.d(TAG,"onCreate");
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.d(TAG,"onStart");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG,"onDestroy");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG,"onBind");
return super.onBind(intent);
}
public interface UpdateUI{
void updateUI(Message message);
}
private Bitmap downloadUrlBitmap(String urlString) {
HttpURLConnection urlConnection = null;
BufferedInputStream in = null;
Bitmap bitmap=null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
bitmap= BitmapFactory.decodeStream(in);
} catch (final IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (in != null) {
in.close();
}
} catch (final IOException e) {
e.printStackTrace();
}
}
return bitmap;
}
}

View File

@ -7,13 +7,13 @@ import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import com.novelbook.android.MyApp;
import com.novelbook.android.db.Chapter;
import com.novelbook.android.db.DownloadTask;
import com.novelbook.android.db.SiteRule;
import com.novelbook.android.netutils.HttpMethods;
import com.novelbook.android.utils.BookUtil;
import com.novelbook.android.utils.FileUtils;
import com.novelbook.android.utils.NovelParseUtil;
import org.json.JSONException;
@ -24,14 +24,15 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.spi.CharsetProvider;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.LogRecord;
import java.util.concurrent.ConcurrentHashMap;
import okhttp3.Call;
import okhttp3.Callback;
@ -47,26 +48,32 @@ public class ServiceDownload extends IntentService {
private final String cachedPath = BookUtil.cachedPath;
private final String chapterPath = BookUtil.chapterPath;
public final String EXTR_TASKID ="taskId";
public final String EXTR_OFFSET ="offset"; //多线程下载每个线程取章节偏移数量
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public ServiceDownload(String name) {
super(name);
}
// public ServiceDownload(String name) {
// super(name);
// }
public ServiceDownload() {
super(TAG);
super("ServiceDownload");
}
private Map<Integer,SiteRule> siteRuleMap = new HashMap<Integer,SiteRule>() ; // key = novelId
private DownloadTask processingTask ;
private int taskIndex=0;
private int chaptIndex=0;
private Map<Integer ,List<Chapter>> tasksMap = new ConcurrentHashMap<Integer, List<Chapter>>();// key = taskId
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"test service onCreate...");
/*
downloadTasks =LitePal.where("status = ?","0").find(DownloadTask.class);
for(DownloadTask dt :downloadTasks){
List<Chapter> chps =Chapter.getUnCachedChapters(dt.getNovelId(),dt.getDomain());
@ -77,37 +84,52 @@ public class ServiceDownload extends IntentService {
}
}
new Thread() {
@Override
public void run() {
}
}.start();
for(DownloadTask tmp: downloadTasks){
Log.d(TAG, String.format("test service task list : %s",tmp.getId()));
}
*/
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.d(TAG,"test service onStart");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"test service onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG,"test service onDestroy");
super.onDestroy();
}
// key = taskId
private Map<Integer ,List<Chapter>> tasksMap = new HashMap<Integer, List<Chapter>>();
private List<DownloadTask> downloadTasks = new ArrayList<DownloadTask>();
@Override
protected void onHandleIntent( Intent intent) {
Log.d(TAG,"test service onHandleIntent...begin");
String key ="taskId";
int taskId =0;
if(intent.hasExtra(key)){
taskId= intent.getExtras().getInt(key);
startNewTask(taskId);
}else{
startTask();
}
else{
/* if(processingTask==null) {
startTask();
}*/
}
Log.d(TAG,"test service onHandleIntent...over");
}
Handler handler = new Handler() {
@Override
@ -115,17 +137,34 @@ public class ServiceDownload extends IntentService {
if(msg.what ==1){
startTask();
}else if(msg.what==2){
if(tasksMap.get(processingTask.getId())==null){
return;
}
Log.d(TAG,String.format("%s start new chapt download---- taskId :%s, chapter count %s,chaptIndex %s",TAG
, processingTask.getId(),
tasksMap.get(processingTask.getId()).size(),chaptIndex ));
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("ServiceDownload.ChapterContent.finished");
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra("progress", processingTask.getFinishedChpats());
broadcastIntent.putExtra("novelId", processingTask.getNovelId());
sendBroadcast(broadcastIntent);
if( tasksMap.get(processingTask.getId()).size()-1 > chaptIndex){
chaptIndex++;
}else{
Log.d(TAG,String.format("%s task done ---- taskId :%s, chapter count %s,chaptIndex %s",TAG , processingTask.getId(),
tasksMap.get(processingTask.getId()).size(),chaptIndex ));
//章节全部处理完毕了
processingTask.setStatus(1);
processingTask.update(processingTask.getId());
tasksMap.remove(processingTask.getId()); //会不会线程冲突
startTask();
}
@ -136,18 +175,20 @@ public class ServiceDownload extends IntentService {
};
// key = novelId
Map<Integer,SiteRule> siteRuleMap = new HashMap<Integer,SiteRule>() ; ;
DownloadTask processingTask ;
int taskIndex=0;
private void startTask() {
if(downloadTasks.size() <=taskIndex){
private void startTask() {
if(processingTask!=null) {
processingTask.update(processingTask.getId());
}
if(downloadTasks.size() <=taskIndex){
processingTask =null;
Log.d(TAG,"No task to download.");
return;
}
processingTask = downloadTasks.get(taskIndex);
chaptIndex=0;
doDownloadContent();
@ -157,7 +198,7 @@ public class ServiceDownload extends IntentService {
}
int chaptIndex=0;
void doDownloadContent(){
Log.d(TAG, String.format("ServiceDowload--- taskId: %s ",processingTask.getId()));
@ -172,6 +213,8 @@ public class ServiceDownload extends IntentService {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
// } catch (IOException e) {
// e.printStackTrace();
}
} else {
@ -182,37 +225,50 @@ public class ServiceDownload extends IntentService {
}
}
synchronized void startNewTask(int taskId){
void startNewTask(int taskId){
DownloadTask dt = LitePal.find(DownloadTask.class,taskId);
if(dt!=null){
List<Chapter> chps = Chapter.getUnCachedChapters(dt.getNovelId(),dt.getDomain() );
if(chps==null || chps.size()==0){
return;
}
SiteRule siteRule = SiteRule. getSiteRuleByDomain(dt.getDomain());
if(siteRule==null){
//to do get siterule from web
}else {
siteRuleMap.put(dt.getNovelId(),siteRule);
downloadTasks.add(dt);
for(DownloadTask tmp: downloadTasks){
Log.d(TAG, String.format("test service task list : %s",tmp.getId()));
}
tasksMap.put(dt.getId(), chps);
if(taskIndex==0) {
startTask();
// handler.sendEmptyMessage(1);
}
}
}
/*
new Thread() {
@Override
public void run() {
DownloadTask dt = LitePal.find(DownloadTask.class,taskId);
if(dt!=null){
SiteRule siteRule = SiteRule. getSiteRuleByDomain(dt.getDomain());
if(siteRule==null){
//to do get siterule from web
}else {
siteRuleMap.put(dt.getNovelId(),siteRule);
List<Chapter> chps = Chapter.getUnCachedChapters(dt.getNovelId(),dt.getDomain() );
downloadTasks.add(dt);
tasksMap.put(dt.getId(), chps);
if(taskIndex==0) {
handler.sendEmptyMessage(1);
}
}
}
}
}.start();
*/
}
private void ServiceDownload( Chapter chapter ) throws JSONException, InterruptedException {
int msg =2;
String url = chapter.getChapterUrl();
@ -225,7 +281,7 @@ public class ServiceDownload extends IntentService {
// Log.d( "ServiceDowload",String.format("ServiceDowload isDownloadChapt: %s",isDownloadChapt));
// Log.d( "ServiceDowload",String.format("ServiceDowload isDownloadChapt: %s",isDownloadChapt));
JSONObject siteJson = new JSONObject();
siteJson.put("chapterContentRegex", siteRuleMap.get(chapter.getNovelId()).getChapterContentRegex());
siteJson.put("chapterContentDumpRegex", siteRuleMap.get(chapter.getNovelId()).getChapterContentDumpRegex());
@ -236,7 +292,7 @@ public class ServiceDownload extends IntentService {
handler.sendEmptyMessage(msg);
// Log.d( "ServiceDowload",String.format("ServiceDowload fail, isDownloadChapt: %s",isDownloadChapt));
// Log.d( "ServiceDowload",String.format("ServiceDowload fail, isDownloadChapt: %s",isDownloadChapt));
e.printStackTrace();
// throw new RuntimeException("Error during writing " + fileChapterName( index));
}
@ -247,9 +303,9 @@ public class ServiceDownload extends IntentService {
if (body != null ) {
if(response.code()!=200){
Log.d(TAG, "ServiceDowload----network failure returnCode " + response.code());
// setDownloadFlag(true);
// chaptDownStatus.put(index, BookUtil.DownloadStatus.failure);
// Log.d( "ServiceDowload",String.format("ServiceDowload error %s ,isDownloadChapt: %s", response.code(),isDownloadChapt));
// setDownloadFlag(true);
// chaptDownStatus.put(index, BookUtil.DownloadStatus.failure);
// Log.d( "ServiceDowload",String.format("ServiceDowload error %s ,isDownloadChapt: %s", response.code(),isDownloadChapt));
handler.sendEmptyMessage(msg);
return;
}
@ -266,18 +322,19 @@ public class ServiceDownload extends IntentService {
writer.write(buf);
writer.close();
Log.d( "ServiceDowload",String.format("ServiceDowload file created: %s", file.getPath()));
processingTask.setFinishedChpats(processingTask.getFinishedChpats()+1);
processingTask.update(processingTask.getId());
Thread.sleep(siteRuleMap.get(chapter.getNovelId()).getMiniInterval4AccessChapter());
// setDownloadFlag(true);
// setDownloadFlag(true);
} catch (IOException | JSONException | InterruptedException e) {
e.printStackTrace();
// throw new RuntimeException("Error during writing " + fileChapterName( index));
// throw new RuntimeException("Error during writing " + fileChapterName( index));
}
finally {
body.close();
// setDownloadFlag(true);
// setDownloadFlag(true);
}
chapter.setChapterPath(fileChapterName(chapter));
@ -285,7 +342,7 @@ public class ServiceDownload extends IntentService {
handler.sendEmptyMessage(msg);
//setDownloadFlag(true);
// chaptDownStatus.put(index, BookUtil.DownloadStatus.success);
// chaptDownStatus.put(index, BookUtil.DownloadStatus.success);
Log.d(TAG,String.format("ServiceDowload---- finished download %s, cost time %s ,content path %s ", chapter.getChapterName(), new Date().getTime() -startTime ,chapter.getChapterPath() ));
}
@ -295,6 +352,83 @@ public class ServiceDownload extends IntentService {
}
/**
* 直接
* @param chapter
* @throws JSONException
* @throws InterruptedException
private void ServiceDownload2( Chapter chapter ) throws IOException, JSONException, InterruptedException {
int msg = 2;
String url = chapter.getChapterUrl();
if (TextUtils.isEmpty(url)) {
handler.sendEmptyMessage(msg);
return;
}
long startTime = new Date().getTime();
Log.d(TAG, String.format("ServiceDowload----start download %s from %s", chapter.getChapterName(), url));
// Log.d( "ServiceDowload",String.format("ServiceDowload isDownloadChapt: %s",isDownloadChapt));
JSONObject siteJson = new JSONObject();
siteJson.put("chapterContentRegex", siteRuleMap.get(chapter.getNovelId()).getChapterContentRegex());
siteJson.put("chapterContentDumpRegex", siteRuleMap.get(chapter.getNovelId()).getChapterContentDumpRegex());
Request request = getTagRequest(url);
Response response = HttpMethods.getOkClient().newCall(request).execute();
ResponseBody body = response.body();
if (body != null) {
if (response.code() != 200) {
Log.d(TAG, "ServiceDowload----network failure returnCode " + response.code());
// setDownloadFlag(true);
// chaptDownStatus.put(index, BookUtil.DownloadStatus.failure);
// Log.d( "ServiceDowload",String.format("ServiceDowload error %s ,isDownloadChapt: %s", response.code(),isDownloadChapt));
handler.sendEmptyMessage(msg);
return;
}
try {
String bodyStr = body.string();
String title = chapter.getChapterName();
String chapterContent = title + "\n" + NovelParseUtil.getChapterContent(bodyStr, siteJson);
char[] buf = chapterContent.toCharArray();
File file = new File(fileChapterName(chapter));
file.createNewFile();
final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileChapterName(chapter)), "utf-8");//"UTF-16LE"); // UTF-16LE utf-8 文件小
writer.write(buf);
writer.close();
Log.d("ServiceDowload", String.format("ServiceDowload file created: %s", file.getPath()));
processingTask.setFinishedChpats(processingTask.getFinishedChpats() + 1);
processingTask.update(processingTask.getId());
Thread.sleep(siteRuleMap.get(chapter.getNovelId()).getMiniInterval4AccessChapter());
// setDownloadFlag(true);
} catch (IOException | JSONException | InterruptedException e) {
e.printStackTrace();
// throw new RuntimeException("Error during writing " + fileChapterName( index));
} finally {
body.close();
// setDownloadFlag(true);
}
chapter.setChapterPath(fileChapterName(chapter));
chapter.update(chapter.getId());
handler.sendEmptyMessage(msg);
//setDownloadFlag(true);
// chaptDownStatus.put(index, BookUtil.DownloadStatus.success);
Log.d(TAG, String.format("ServiceDowload---- finished download %s, cost time %s ,content path %s ", chapter.getChapterName(), new Date().getTime() - startTime, chapter.getChapterPath()));
}
}
*/
protected String fileChapterName(Chapter chapter ) {
return getChapterPath(chapter.getNovelId()) +chapter.getDomain()+"/"+ chapter.getIndex() ;

View File

@ -78,17 +78,17 @@ import butterknife.ButterKnife;
holder.tvTitle.setText(mDatas.get(0).getName());
holder.tvAuthor.setText(mDatas.get(0).getAuthor());
holder.tvCate.setText(mDatas.get(0).getNovelType());
holder.tvDesc.setText(mDatas.get(0).getDescription());
holder.tvDesc.setText(mDatas.get(0).getDesc());
holder.tvTitle2.setText(mDatas.get(1).getName());
holder.tvAuthor2.setText(mDatas.get(1).getAuthor());
holder.tvCate2.setText(mDatas.get(1).getNovelType());
holder.tvDesc2.setText(mDatas.get(1).getDescription());
holder.tvDesc2.setText(mDatas.get(1).getDesc());
holder.tvTitle3.setText(mDatas.get(2).getName());
holder.tvAuthor3.setText(mDatas.get(2).getAuthor());
holder.tvCate3.setText(mDatas.get(2).getNovelType());
holder.tvDesc3.setText(mDatas.get(2).getDescription());
holder.tvDesc3.setText(mDatas.get(2).getDesc());
// 如果设置了回调则设置点击事件
if (mOnItemClickLitener != null)

View File

@ -258,7 +258,7 @@ public class BookUtil {
//TODO 构建新的缓存策略几个选项1每本书一个缓存 2控制缓存总大小超过限制删除旧缓存 3网络小说的缓存
boolean isLocalImport = TextUtils.isEmpty( novel.getNovelId());
boolean isLocalImport = novel.isLocalBook();
boolean isOnShelf = isLocalImport || novel.isOnShelf();
boolean isLoadChaptsFromRemote = !isLocalImport ;// && !novel.isFinished() ; //是否从目标网站下载目录
// showProgressDialog();

View File

@ -11,14 +11,14 @@ public class GsonUtil {
Novel nv = new Novel();
try {
JSONObject jsonObject = new JSONObject(json);
nv.setNovelId(jsonObject.getString("novelId"));
nv.setNovelId(jsonObject.getInt("novelId"));
nv.setLastUpateTime(jsonObject.getLong("lastUpateTime"));
nv.setAuthor(jsonObject.getString("author"));
nv.setName(jsonObject.getString("name"));
nv.setCover(jsonObject.getString("cover"));
nv.setNovelType(jsonObject.getString("novelType"));
nv.setNovelType2(jsonObject.getString("novelType2"));
nv.setLastestChapterName(jsonObject.getString("lastestChapterName"));
nv.setSmallNovelType(jsonObject.getString("novelType2"));
nv.setChapterName(jsonObject.getString("lastestChapterName"));
return nv;

View File

@ -555,7 +555,7 @@ public class PageFactory {
public void prepareBook(Novel book){
if(mBook!=null &&mBook.getNovelId() !=book.getNovelId()){ //取消未上本书完成的web请求待验证效果
NetUtil.cancelRequest(mBook.getNovelId());
NetUtil.cancelRequest(mBook.getNovelId()+"" );
}
mBookUtil = new BookUtil();
//this.mBookUtil.setContext(context);
@ -579,7 +579,7 @@ public class PageFactory {
initBg(config.getDayOrNight());
if(mBook!=null &&mBook.getNovelId() !=book.getNovelId()){ //取消未上本书完成的web请求
NetUtil.cancelRequest(mBook.getNovelId());
NetUtil.cancelRequest(mBook.getNovelId()+"" );
}
this.mBook = book ;

View File

@ -58,6 +58,8 @@
android:layout_height="wrap_content"
android:gravity="bottom"
android:layout_gravity="center"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:orientation="horizontal">