package com.novelbook.android.utils; import android.app.ProgressDialog; import android.content.ContentValues; import android.content.Context; import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import com.google.gson.Gson; import com.novelbook.android.BookActivity; import com.novelbook.android.MyApp; import com.novelbook.android.bean.Cache; import com.novelbook.android.bean.NovelSites; import com.novelbook.android.bean.Site; import com.novelbook.android.db.SiteRule; import com.novelbook.android.db.Chapter; import com.novelbook.android.db.Novel; import com.novelbook.android.netsubscribe.BookSubscribe; import com.novelbook.android.netutils.HttpMethods; import com.novelbook.android.netutils.OnSuccessAndFaultListener; import com.novelbook.android.netutils.OnSuccessAndFaultSub; import org.json.JSONException; import org.json.JSONObject; import org.litepal.LitePal; import java.io.Console; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; public class BookUtil { public static final String TAG ="BookUtil"; public static final String storagePath = FileUtils.getDiskCacheDir(MyApp.applicationContext);//Environment.getExternalStorageDirectory() + "/zhuike"; public static final String cachedPath = storagePath + "/cache/"; public static final String chapterPath = storagePath + "/chapter/"; private static final String charachterType = "utf-8";//"UTF-16LE"; private Context mContext; private ProgressDialog progressDialog; private MuluStatus mMuluStatus; //目录是否下载完成 private Gson gson = new Gson(); public void setContext(Context context) { this.mContext = context; } public boolean isReadingCatalogs() { return mMuluStatus == MuluStatus.isDownloading; } //存储的字符数 public static final int cachedSize = 30000; // protected final ArrayList> myArray = new ArrayList<>(); public static final String lineBreakChar ="\n"; protected final ArrayList myArray = new ArrayList<>(); //目录 private List mChapters = new ArrayList<>(); //当前章节 // private Chapter mCurrentChapter; public List getChapters() { return mChapters; } public void setChapters(List chapters) { this.mChapters = chapters; } private String m_strCharsetName; private String bookName; private String bookPath; public void setBookLen(long bookLen) { this.bookLen = bookLen; } private long bookLen; private long position; private Novel mNovel; public void setNovel(Novel novel) { this.mNovel = novel; } public Novel getNovel( ) { return mNovel ; } //当前目录网站列表 private NovelSites mNovelSites; //当前目录网站 private Site mSite; private SiteRule mSiteRule; public NovelSites getmNovelSites() { return mNovelSites; } public synchronized void openBook(Novel novel) throws IOException, InterruptedException { this.mNovel = novel; //如果当前缓存不是要打开的书本就缓存书本同时删除缓存 //TODO 构建新的缓存策略,几个选项,1:每本书一个缓存 2:控制缓存总大小,超过限制删除旧缓存 3:网络小说的缓存 boolean isLocalImport = novel.isLocalBook(); boolean isOnShelf = isLocalImport || novel.isOnShelf(); boolean isLoadChaptsFromRemote = !isLocalImport ;// && !novel.isFinished() ; //是否从目标网站下载目录 // showProgressDialog(); if(isLocalImport) { mChapters = LitePal.where("novelId=?", mNovel.getId() + "").find(Chapter.class); for (Chapter c : mChapters) { Log.d(TAG, String.format("bookchapter :%s,fileName :%s, chapter Size %s", c.getChapterName(), c.getChapterPath(), c.getLength())); } chaptCache = new HashMap(); if (mChapters.isEmpty()) { //1. 首次打开 本地导入的书 if (bookPath == null || !bookPath.equals(mNovel.getNovelPath())) { cleanCacheFile(); this.bookPath = mNovel.getNovelPath(); bookName = FileUtils.getFileName(bookPath); cacheBook(); } } }else{ //读取目录列表 MuluStatus m = mMuluStatus; // Log.d(TAG,String.format("mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus)); Log.d(TAG, String.format("prepare book %s open book in background.... mMuluStatus %s,mSiteRule %s,thread %s",mNovel.getName(),mMuluStatus,mSiteRule,Thread.currentThread().getName()) ); while( mSiteRule ==null || mMuluStatus==null || mMuluStatus == MuluStatus.isDownloading){ Thread.sleep(50); Log.d(TAG,String.format("prepare book %s waiting for mulu downloading ,mMuluStatus %s,msiteRule %s" ,mNovel.getName(),mMuluStatus,mSiteRule)); if(mMuluStatus == MuluStatus.failed){ dismissProgressDialog(); throw new RuntimeException("读取资源失败,请检查网络"); } } } // dismissProgressDialog(); } public void setNovelSites(NovelSites nvs) { this.mNovelSites = nvs; Log.d(TAG, String.format("prepare book %s get novel sites count %s .",mNovel.getName(), nvs.getSites().length) ); if(nvs.getSites().length ==0){ throw new RuntimeException("书本错误 code 001"); //无目标网站 // return; } mSite =nvs.getSites()[0]; if(nvs.getSites().length > 0) for (Site site:nvs.getSites() ) { if(site.getSelectedByDefault()){ mSite = site; break; } } getSiteRule(); } private void setSiteInfo() { File file = new File(getChapterPath() +mSite.getDomain()); if(!file.exists()){ file.mkdir(); } mNovel.setDomain(mSite.getDomain()); mNovel.setMuluUrl(mSite.getMuluUrl()); mNovel.update(mNovel.getId()); } public void getTargetSites(){ BookSubscribe.getNovelSites(mNovel.getNovelId(),new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() { @Override public void onSuccess(String result) { //成功 try { Log.d(TAG, String.format("prepare book %s get target sites done.thread %s",mNovel.getName(),Thread.currentThread().getName()) ); NovelSites nvs = (NovelSites) gson.fromJson(result,NovelSites.class); //pageFactory.prepareBook(mNovel,nvs, BookActivity.this); setNovelSites(nvs); } catch ( Exception e) { Log.d(TAG, String.format("prepare book %s get target sites fail.thread %s ,msg %s",mNovel.getName(),Thread.currentThread().getName(),e.getMessage()) ); Log.e(TAG, "prepare book fail", e); e.printStackTrace(); } // Toast.makeText(mContext,"getMuluInfo 请求成功 " ,Toast.LENGTH_SHORT).show(); } @Override public void onFault(String errorMsg) { //失败 // Toast.makeText(mContext,"getMuluInfo 请求失败"+errorMsg,Toast.LENGTH_SHORT).show(); } },null)); } private void getSiteRule() { mSiteRule = null; BookSubscribe.getSiteRule(mSite.getDomain(),new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() { @Override public void onSuccess(String result) { //成功 SiteRule sr = (SiteRule)gson.fromJson(result,SiteRule.class); List srs = LitePal.where("domain=?",sr.getDomain()).limit(1).find(SiteRule.class); long id = srs.size()==1 ?srs.get(0).getId() :0; if(id>0 ){ sr.update(id); // mSiteRule =LitePal.find(SiteRule.class,id); }else { sr.save(); } mSiteRule =sr; setSiteInfo(); Log.d(TAG, String.format("prepare book %s 目录正则表达式下载完成,开始读章节信息. thread %s ",mNovel.getName(),Thread.currentThread().getName()) ); Log.d(TAG, String.format("目录正则表达式下载完成,开始读取章节信息") ); readChaptersAsync(); } @Override public void onFault(String errorMsg) { //失败 Log.d(TAG,"error on get sitRule: "+errorMsg); } },mContext)); /* if(mSiteRule==null && mSite!=null) { List srs = LitePal.where("domain=?", mSite.getDomain()).find(SiteRule.class); if (srs.size() > 0) { mSiteRule = srs.get(0); } }*/ } public void setChapterNo(int chapterNo) { this.chapterNo = chapterNo; /* if(chapterNo <= mChapters.size()) { this.chapterNo = chapterNo; }else{ Log.d(TAG, String.format("setChapterNo: wrong chapno for book %s,site %s,total chapts %s,chaptNo %s" ,mNovel.getName(),mNovel.getDomain(),getChapters().size(),chapterNo)); } */ } public int getChapterNo() { if(chapterNo > mChapters.size()){ chapterNo =1; } return chapterNo; } private int chapterNo;//当前章节 public String getLineBreakChar(){ return "\n"; } public BookUtil(){ checkAndCreateDir(storagePath); checkAndCreateDir(chapterPath); checkAndCreateDir(cachedPath); } public boolean isBusy() { return false; } private boolean isChangeSource =false; private int mChangeChapId; private String mChangeTitle; public void changeSource(String domain,int chapId,String chapTitle) { Log.d(TAG, String.format("changing Source: target domain %s chaptId %s, chapt title %s ",domain,chapId,chapTitle) ); if(mSite.getDomain().equals(domain)){ //当前源 Log.d(TAG, "changing Source: same site with original " + domain); return; } mChangeChapId = chapId; mChangeTitle =chapTitle; for (Site site:mNovelSites.getSites() ) { if(site.getDomain().equals(domain)){ mSite = site; break; } } setSiteInfo(); showProgressDialog("正在换源",false); isChangeSource = true; mChapters.clear(); getSiteRule(); BookTask btsk = new BookTask(); btsk.execute( domain, chapId+"", chapTitle); } public String getSite() { return mSite !=null? mSite.getDomain():""; } private class BookTask extends AsyncTask { private String domain; private int chapId; private String chapTitle; @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); Log.d("onPostExecute",isCancelled() + ""); if (isCancelled()){ return; } if (result) { Log.d(TAG, "changing Source:successed get chapters for " + mSite.getDomain() ); int chId=chapterNo; String title =""; if( mChapters.size() >= mChangeChapId && mChapters.get(mChangeChapId-1)!=null ){ title= mChapters.get(mChangeChapId-1).getChapterName(); Log.d(TAG, "changing Source:chapter name in new site " + title ); } if(title.equals(mChangeTitle)) { Log.d(TAG, "changing Source:successed find chapter by original chaptId " + mChangeChapId + ":" + mChangeTitle); chId = mChangeChapId; } else { int i = 1; for (Chapter chapter : mChapters) { Log.d(TAG, "changing Source: finding chapter " + i + ":" + chapter.getChapterName()); if (chapter.getChapterName().equals(mChangeTitle)) { Log.d(TAG, "changing Source:successed find chapter by original title " + i + ":" + mChangeTitle); chId = i; break; } i++; } } chId = chId <= mChapters.size() ? chId: mChapters.size(); Log.d(TAG, "changing Source: to open chapter with new site source " + chId + " : "+ mChangeTitle ); pagefactory.changeChapter(chId); Toast.makeText(mContext,"换源成功",Toast.LENGTH_LONG).show(); }else{ Log.d(TAG, "changing Source: failed " ); } } @Override protected Boolean doInBackground(String... params) { domain = params[0]; chapId = Integer.parseInt( params[1]); chapTitle = params[2]; int splet =0; while(isChangeSource){ try { Thread.sleep(50); splet++; Log.d(TAG, String.format("changing Source slept %s,isChangeSource %s ", splet, isChangeSource )); } catch (InterruptedException e) { e.printStackTrace(); } } return true; } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); } } /** * 新线程换源 ,handler 有问题 * @param domain * @param chapId * @param chapTitle */ public void changeSourceNewThread(String domain,int chapId,String chapTitle) { Log.d(TAG, String.format("changing Source: target domain %s chaptId %s, chapt title %s ",domain,chapId,chapTitle) ); if(mSite.getDomain().equals(domain)){ //当前源 Log.d(TAG, "changing Source: same site with original " + domain); // return; } mChangeChapId = chapId; mChangeTitle =chapTitle; for (Site site:mNovelSites.getSites() ) { if(site.getDomain().equals(domain)){ mSite = site; break; } } setSiteInfo(); // showProgressDialog(); isChangeSource = true; new Thread(){ @Override public void run() { Log.d(TAG, "changing Source: to get site rule" ); getSiteRule(); } }.start(); /* while(isChangeSource){ try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } new Thread(){ @Override public void run() { Log.d(TAG, "changing Source: to get site rule" ); getSiteRule(); } }.start();*/ } enum MuluStatus{ isDownloading, isDone, failed } private void showProgressDialog(String title,boolean canBreak) { if ( null == progressDialog) { progressDialog =new ProgressDialog(mContext); } progressDialog.setMessage(title); progressDialog.setCancelable(canBreak); progressDialog.show(); // progressDialog.show(mContext,"网络不给力","正努力加载",false,true); } private void dismissProgressDialog() { if ( null != progressDialog) { progressDialog.dismiss(); } } private void checkAndCreateDir(String path){ File file = new File(path); if (!file.exists()){ file.mkdir(); } } void readChaptersAsync( ) { String url = mSite.getMuluUrl(); Request request = getTagRequest(url); mMuluStatus = MuluStatus.isDownloading; long startTime= new Date().getTime(); Log.d(TAG,String.format("loadChapts----start download %s 目录 from %s", mNovel.getName() ,url )); HttpMethods.getOkClient().newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // Log.d(TAG, "onFailure: " + e.getMessage()); Log.e(TAG, "loadChapts---- failed: ",e ); Log.d(TAG,String.format("loadChapts---- failed %s 目录 from %s", mNovel.getName() ,url )); handler.sendEmptyMessage(3); //TODO 如果是取消了访问,则返回 if( mNovelSites.getSites().length ==1){ //仅有一个rule,且失败了 mMuluStatus = MuluStatus.failed; return; } //try next site for(Site st : mNovelSites.getSites() ){ if(!st.getDomain().equals(mSite.getDomain())){ mSite =st; break; } } // readChaptersAsync(); getSiteRule(); } @Override public void onResponse(Call call, Response response){ ResponseBody body = response.body(); if(response.code()!=200){ Log.d(TAG,String.format("loadChapts----failed, %s 目录 from %s,return code %s", mNovel.getName() ,url,response.code() )); handler.sendEmptyMessage(3); mMuluStatus = MuluStatus.failed; return; } if (body != null) { Log.d(TAG, String.format("prepare book %s 章节信息读取成功.thread %s",mNovel.getName(),Thread.currentThread().getName()) ); try { String bodyStr = body.string(); // Log.d(TAG, "onResponse: " +bodyStr); // Log.d(TAG,String.format("loadChaptContent----end download %s 目录, 目录数量 %s, cost %s", mNovel.getName() , mChapters.size(), new Date().getTime() -startTime )); // long startTime2= new Date().getTime(); buildChapters(bodyStr,url); Log.d(TAG,String.format("loadChapts----end download %s 目录, 目录数量 %s, cost %s", mNovel.getName() , mChapters.size(), new Date().getTime() -startTime )); mMuluStatus = MuluStatus.isDone; Log.d(TAG, String.format("prepare book %s 章节信息完成.",mNovel.getName()) ); } catch (IOException e) { e.printStackTrace(); }finally { body.close(); handler.sendEmptyMessage(3); } } } }); } void buildChapters( String content ,String url){ try { JSONObject siteJson = new JSONObject(); siteJson.put("chapterUrlPattern", mSiteRule.getChapterUrlPattern()); siteJson.put("chapterUrlRegexOnMulu", mSiteRule.getChapterUrlRegexOnMulu());//示例接口表达式有问题 // siteJson.put("chapterUrlRegexOnMulu", "
]*href=\"(/book/[\\d]+/[\\d]+\\.html)\">([^<]+)
"); siteJson.put("chapterUrlRegexOnMulu", mSiteRule.getChapterUrlRegexOnMulu()); mChapters = NovelParseUtil.getChapters(mSite.getDomain(),url, content, siteJson); Log.d(TAG,String.format("mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus)); /* if (mChapters != null) { int lastReadChapt = mNovel.getLastReadChapt(); // int index =lastReadChapt*2-2; lastReadChapt = lastReadChapt >=mChapters.size() ? mChapters.size() -1:lastReadChapt; lastReadChapt = lastReadChapt <=0 ? 1:lastReadChapt; mCurrentChapter =mChapters.get(lastReadChapt-1); }*/ } catch (JSONException e) { // } catch (JSONException | IOException e) { Log.d(TAG,String.format("mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus)); e.printStackTrace(); } finally { // result.close(); // if (result2 != null) result2.close(); } } private void cleanCacheFile(){ File file = new File(cachedPath ); if (!file.exists()){ file.mkdir(); }else{ File[] files = file.listFiles(); for (int i = 0; i < files.length;i++){ files[i].delete(); } } file = new File(getChapterPath()); if (!file.exists()){ file.mkdir(); }else{ File[] files = file.listFiles(); for (int i = 0; i < files.length;i++){ files[i].delete(); } } } public int next(boolean back){ position += 1; if (position > bookLen){ position = bookLen; return -1; } char result = chaptCurrent(); //current(); if (back) { position -= 1; } return result; } public char[] nextLine(){ if (position >= bookLen){ return null; } String line = ""; while (position < bookLen){ int word = next(false); if (word == -1){ break; } char wordChar = (char) word; if ((wordChar + "").equals("\n") ){// if ((wordChar + "").equals("\r") && (((char)next(true)) + "").equals("\n")){ // next(false); break; } line += wordChar; } return line.toCharArray(); } public char[] preLine(){ if (position <= 0){ return null; } String line = ""; while (position >= 0){ int word = pre(false); if (word == -1){ break; } char wordChar = (char) word; if ((wordChar + "").equals("\n") ){ // if ((wordChar + "").equals("\n") && (((char)pre(true)) + "").equals("\r")){ // pre(false); // /r/n ->/n 不需要再往前读一个字符了 // line = "\r\n" + line; break; } line = wordChar + line; } return line.toCharArray(); } public char chaptCurrent(){ chapterNo = mChapters.size() < chapterNo ? 1 : chapterNo; char[] charArray = chaptChars(chapterNo); int i = (int)position-1; i = i<= charArray.length? i:charArray.length; return charArray[i]; } public char current(){ // int pos = (int) (position % cachedSize); // int cachePos = (int) (position / cachedSize); int cachePos = 0; int pos = 0; int len = 0; for (int i = 0;i < myArray.size();i++){ long size = myArray.get(i).getSize(); if (size + len - 1 >= position){ cachePos = i; pos = (int) (position - len); break; } len += size; } char[] charArray = block(cachePos); return charArray[pos]; } public int pre(boolean back){ position -= 1; if (position < 0){ position = 0; return -1; } char result = current(); if (back) { position += 1; } return result; } public long getPosition(){ return position; } public void setPostition(long position){ this.position = position; } //缓存书本 private void cacheBook() throws IOException { if (TextUtils.isEmpty(mNovel.getCharset())) { m_strCharsetName = FileUtils.getCharset(bookPath); if (m_strCharsetName == null) { m_strCharsetName = "utf-8"; } ContentValues values = new ContentValues(); values.put("charset",m_strCharsetName); LitePal.update(Novel.class,values,mNovel.getId()); }else{ m_strCharsetName = mNovel.getCharset(); } File file = new File(bookPath); InputStreamReader reader = new InputStreamReader(new FileInputStream(file),m_strCharsetName); int index = 0; bookLen = 0; mChapters.clear(); myArray.clear(); while (true){ char[] buf = new char[cachedSize]; int result = reader.read(buf); if (result == -1){ reader.close(); break; } String bufStr = new String(buf); // Log.e(TAG,String.format("缓存的内容是\n %s",bufStr)); bufStr = bufStr.replaceAll("\r\n","\n"); // bufStr = bufStr.replaceAll("\u3000\u3000+[ ]*","\u3000\u3000"); bufStr = bufStr.replaceAll("\n+\\s*","\n\u3000\u3000");// bufStr = bufStr.replaceAll("\r\n+\\s*","\r\n\u3000\u3000"); // bufStr = bufStr.replaceAll("\r\n[ {0,}]","\r\n\u3000\u3000"); // bufStr = bufStr.replaceAll(" ",""); bufStr = bufStr.replaceAll("\u0000",""); buf = bufStr.toCharArray(); bookLen += buf.length; // Log.e(TAG,String.format("缓存的内容脱空格处理后\n %s",bufStr)); Cache cache = new Cache(); cache.setSize(buf.length); cache.setData(new WeakReference(buf)); // bookLen += result; myArray.add(cache); // myArray.add(new WeakReference(buf)); // myArray.set(index,); Log.e(TAG,String.format("缓存的内容写入文件\n %s",fileName(index))); Log.e(TAG,"---------------------------------------------------------------------------------------------------------"); try { File cacheBook = new File(fileName(index)); if (!cacheBook.exists()){ cacheBook.createNewFile(); } final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileName(index)), "UTF-16LE"); // UTF-16LE 比 utf-8 文件小 writer.write(buf); writer.close(); } catch (IOException e) { throw new RuntimeException("Error during writing " + fileName(index)); } index ++; } chaptId =0; //初始化导入的chapid int endchp = myArray.size()>3 ?3:myArray.size(); getChapter(1,3); //先导入2个部分 立即进行阅读 new Thread(){ @Override public void run() { getChapter(4,myArray.size()); //剩余部分后台导入 } }.start(); } int chaptId =0; //获取章节 public synchronized void getChapter(int startblk,int endblk){ if(endblk getmChapters(){ return mChapters; } public long getBookLen(){ return bookLen; } protected String fileName(int index) { return cachedPath + mNovel.getName() + index ; } protected String fileChapterName(int chaptId ) { if(!TextUtils.isEmpty(mNovel.getDomain())){ return getChapterPath() +mNovel.getDomain()+"/"+ chaptId ; } return getChapterPath() + chaptId ; } String getChapterPath(){ File file = new File(chapterPath +mNovel.getId()); if(!file.exists()){ file.mkdir(); } return chapterPath +mNovel.getId()+"/"; } //获取书本缓存 public char[] block(int index) { if (myArray.size() == 0){ return new char[1]; } char[] block = myArray.get(index).getData().get(); if (block == null) { try { File file = new File(fileName(index)); int size = (int)file.length(); if (size < 0) { throw new RuntimeException("Error during reading " + fileName(index)); } block = new char[size / 2]; InputStreamReader reader = new InputStreamReader( new FileInputStream(file), "UTF-16LE" ); if (reader.read(block) != block.length) { throw new RuntimeException("Error during reading " + fileName(index)); } reader.close(); } catch (IOException e) { throw new RuntimeException("Error during reading " + fileName(index)); } Cache cache = myArray.get(index); cache.setData(new WeakReference(block)); // myArray.set(index, new WeakReference(block)); } return block; } boolean isDownloadChapt =false; synchronized boolean getDownloadStatus(){ return isDownloadChapt; } synchronized void setDownloadFlag(boolean flag){ isDownloadChapt = flag; Log.d("loadChaptContent",String.format("set download flat",isDownloadChapt) ); } public ChangeSource pagefactory; Handler handler = new Handler() { @Override public void handleMessage(Message msg) { int wt = msg.what; handlerMsg(msg); dismissProgressDialog(); } }; void handlerMsg(Message msg){ if (msg.what == 123) { isDownloadChapt =true; Log.d("loadChaptContent",String.format("handler msg, download %s",isDownloadChapt) ); }else if(msg.what==1){ isDownloadChapt =true; // Toast.makeText(mContext,"网络错误",Toast.LENGTH_LONG).show(); }else if(msg.what==3){ //change source isChangeSource =false; Log.d(TAG, "changing Source:successed get chapters for " + mSite.getDomain() ); /*if(isChangeSource){ Log.d(TAG, "changing Source:successed get chapters for " + mSite.getDomain() ); isChangeSource =false; int chapId=chapterNo; if( mChapters.size() >= mChangeChapId && mChapters.get(mChangeChapId-1)!=null ){ String title = mChapters.get(mChangeChapId-1).getChapterName(); Log.d(TAG, "changing Source:chapter name in new site " + title ); if(title.equals(mChangeTitle)) { Log.d(TAG, "changing Source:successed find chapter by original chaptId " + mChangeChapId + ":" + mChangeTitle); chapId = mChangeChapId; } }else{ int i =1; for (Chapter chapter : mChapters) { if (chapter.getChapterName().equals(mChangeTitle)) { Log.d(TAG, "changing Source:successed find chapter by original title " +i + ":"+ mChangeTitle ); chapId = i; break; } i++; } } chapId = chapId <= mChapters.size() ? chapId: mChapters.size(); Log.d(TAG, "changing Source: to open chapter with new site source " + chapId + " : "+ mChangeTitle ); pagefactory.changeChapter(chapId); } */ } } private Map chaptCache = new HashMap(); private Map chaptDownStatus = new HashMap(); DownloadStatus downloadStatus = DownloadStatus.notStart; private enum DownloadStatus{ notStart, downloading, failure, success } public boolean isChapterContentExist(int index) { char[] block = null; if (chaptCache.containsKey(Integer.valueOf(index))) { block = chaptCache.get(index).getData().get(); } if (block == null) { // cleanCacheFile(); //to remove File file = new File(fileChapterName(index)); if (!file.exists()) { showProgressDialog("请稍候",false); new Thread(){ @Override public void run() { try { loadChaptContent(index); } catch (JSONException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); return false; } } return true; } //获取chapter 缓存 public char[] chaptChars(final int index) { char[] block=null; if(chaptCache.containsKey(Integer.valueOf(index))) { block = chaptCache .get(index).getData().get(); } if (block == null) { // cleanCacheFile(); //to remove try { File file = new File(fileChapterName(index)); if(!file.exists()) { if(mMuluStatus ==null){ Log.d(TAG,String.format("prepare book loadChapts---- 还未有目录信息,出错了 %s 目录, 目录数量 %s, MuluStatus %s ,thread %s", mNovel.getName() , mChapters.size(), mMuluStatus,Thread.currentThread().getName() )); // getTargetSites(); } int slept = 0; while(slept <100 && mMuluStatus ==MuluStatus.isDownloading){ try { Thread.sleep(50); slept++; Log.d(TAG,String.format("prepare book loadChapts----等待中 %s 目录, 目录数量 %s, slept %s, MuluStatus %s", mNovel.getName() , mChapters.size(),slept ,mMuluStatus )); } catch (InterruptedException e) { e.printStackTrace(); } } if( mChapters ==null || mChapters.size() ==0){ Log.d(TAG,String.format("loadChapts----超时。。。或出错了 %s 目录, 目录数量 %s, slept %s, MuluStatus %s,thread %s", mNovel.getName() , mChapters.size(),slept ,mMuluStatus,Thread.currentThread().getName() )); String error = " "; return error.toCharArray(); } Log.d(TAG,String.format("loadChaptContent----start %s" ,new Date().toString() )); Log.d( "loadChaptContent",String.format("begin to load content for chapter %s",index)); Log.d( "loadChaptContent",String.format("isDownloadChapt: %s",isDownloadChapt)); if(!chaptDownStatus.containsKey(Integer.valueOf(index))){ chaptDownStatus.put(index,DownloadStatus.downloading); loadChaptContent(index); } Log.d( "loadChaptContent",String.format("showing dialog " )); // Log.d(TAG,String.format("showing progress diaglog......")); int maxSleep =6000; int slepttime =0; // while(!file.exists() && !getDownloadStatus()){//&& slepttime index ) { File file2 = new File(fileChapterName(index+1)); if(!file2.exists()) { loadChaptContent(index + 1); } } int size = (int)file.length(); if (size < 0) { throw new RuntimeException("Error during reading " + fileChapterName(index)); } block = new char[size / 2]; InputStreamReader reader = new InputStreamReader( new FileInputStream(file), charachterType ); long l = reader.read(block); if (reader.read(block) != block.length) { // throw new RuntimeException("Error during reading " + fileChapterName(index)); } reader.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("Error during reading " + fileChapterName(index)); } catch (JSONException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); }finally { dismissProgressDialog(); } Cache cache = new Cache(); cache.setSize(block.length); cache.setData(new WeakReference(block)); chaptCache.put(index, cache); // myArray.set(index, new WeakReference(block)); } return block; } private void loadChaptContent(final int chapterIndex) throws JSONException, InterruptedException { /* 章节内容没有缓存在本地 1. 根据本地的章节网络地址信息,读取章节内容到本地,若读取失败则 2. 查询主服务器,若有地址更新则更新本地信息,并重复1,若没有更新地址,则地址无效,返回章节内容正待手打 */ // final int index = mChapters.size() < chapterIndex ? 1 : chapterIndex; if(mChapters.size()