作为一个资深小说迷和一个优秀的程序猿的我,最近一年都在研究小说阅读器,终于......。
小说类型大致分三种:资源阅读型,本地文件阅读型,网络综合型。
步步递进,我的学习过程也是这样的(文章最后有彩蛋!)
1.首先资源阅读型,就是把一整部小说放进Asset,然后通过context.getAssets(),获取书本
/**
* package: com.example.luoyangcomputer.localbook.modelbook
* created by luoyang
*/
public class BookLab {
public static final String TEXT = "text";
public static final String IMAGE = "image";
private static BookLab sBookLab;
private AssetManager mAssetManager;
private List<Book> mBookList;
//assets中的文件名清单
private String[] mAssetsImageList;
private String[] mAssetsTextList;
private BookLab(Context context) {
mAssetManager = context.getAssets();
loadAssetsFiles();
}
public static BookLab newInstance(Context context) {
if (sBookLab == null) {
sBookLab = new BookLab(context);
}
return sBookLab;
}
//加载assets中的文件
private void loadAssetsFiles() {
mBookList = new ArrayList<>();
//获取image、text中的文件名清单
try {
mAssetsImageList = mAssetManager.list(IMAGE);
mAssetsTextList = mAssetManager.list(TEXT);
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < mAssetsTextList.length; i++) {
//获取书名
String[] nameSplit = mAssetsTextList[i].split("_");
String nameSecond = nameSplit[nameSplit.length - 1];
String bookTitle = nameSecond.replace(".txt", "");
//获取封面
String imagePath = IMAGE + "/" + mAssetsImageList[i];
Bitmap bookCover = loadImage(imagePath);
//获取文本
String textPath = TEXT + "/" + mAssetsTextList[i];
String bodyText = loadText(textPath);
Book book = new Book(bookTitle, bookCover, bodyText);
mBookList.add(book);
}
}
//从assets中读取文本
private String loadText(String path) {
InputStream in = null;
BufferedReader reader = null;
StringBuilder stringBuilder = new StringBuilder();
try {
in = mAssetManager.open(path);
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return stringBuilder.toString();
}
//从assets中读取图片
private Bitmap loadImage(String path) {
Bitmap image = null;
InputStream in = null;
try {
in = mAssetManager.open(path);
image = BitmapFactory.decodeStream(in);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return image;
}
public List<Book> getBookList() {
return mBookList;
}
}
2,本地文件型获取方式,获取本地小说文件 ,这边是得到txt文件
public class FileUtils {
/**
* 获取文件编码
* @param fileName
* @return
* @throws IOException
*/
public static String getCharset(String fileName) throws IOException{
String charset;
FileInputStream fis = new FileInputStream(fileName);
byte[] buf = new byte[4096];
// (1)
UniversalDetector detector = new UniversalDetector(null);
// (2)
int nread;
while ((nread = fis.read(buf)) > 0 && !detector.isDone()) {
detector.handleData(buf, 0, nread);
}
// (3)
detector.dataEnd();
// (4)
charset = detector.getDetectedCharset();
// (5)
detector.reset();
return charset;
}
/**
* 根据路径获取文件名
* @param pathandname
* @return
*/
public static String getFileName(String pathandname){
int start=pathandname.lastIndexOf("/");
int end=pathandname.lastIndexOf(".");
if(start!=-1 && end!=-1){
return pathandname.substring(start+1,end);
}else{
return "";
}
}
public static List<File> getSuffixFile(String filePath, String suffere){
List<File> files = new ArrayList<>();
File f = new File(filePath);
return getSuffixFile(files,f,suffere);
}
/**
* 读取sd卡上指定后缀的所有文件
* @param files 返回的所有文件
* @param f 路径(可传入sd卡路径)
* @param suffere 后缀名称 比如 .gif
* @return
*/
public static List<File> getSuffixFile(List<File> files, File f, final String suffere) {
if (!f.exists()) {
return null;
}
File[] subFiles = f.listFiles();
for (File subFile : subFiles) {
if (subFile.isHidden()){
continue;
}
if(subFile.isDirectory()){
getSuffixFile(files, subFile, suffere);
}else if(subFile.getName().endsWith(suffere)){
files.add(subFile);
} else{
//非指定目录文件 不做处理
}
// Log.e("filename",subFile.getName());
}
return files;
}
}
3.网络型,Rxjava Retrofit 获取网络小说信息,Jsoup解析
/**
* 该网站搜索小说 s.php?ie=gbk&q=斗罗大陆
*/
@Override
public Observable<List<SearchBookBean>> searchBook(String content, int page) {
return getRetrofitObject(TAG).create(WjduoApi.class).searchBook("gbk", content).flatMap(new Function<String, ObservableSource<List<SearchBookBean>>>() {
@Override
public ObservableSource<List<SearchBookBean>> apply(String s) throws Exception {
return analySearchBook(s);
}
});
}
private ObservableSource<List<SearchBookBean>> analySearchBook(final String s) {
return Observable.create(new ObservableOnSubscribe<List<SearchBookBean>>() {
@Override
public void subscribe(ObservableEmitter<List<SearchBookBean>> emitter) throws Exception {
try {
Document doc = Jsoup.parse(s);
Elements booksE = doc.getElementsByClass("so_list bookcase").get(0).getElementsByClass("bookbox");
if (null != booksE && booksE.size() >= 1) {
List<SearchBookBean> books = new ArrayList<SearchBookBean>();
for (int i = 0; i < booksE.size(); i++) {
SearchBookBean item = new SearchBookBean();
Element booksEP10 = booksE.get(i).getElementsByClass("p10").get(0);
item.setTag(TAG);
item.setCoverUrl(TAG + booksEP10.getElementsByClass("bookimg").get(0).getElementsByTag("a")
.get(0).getElementsByTag("img").get(0).attr("src"));
item.setNoteUrl(TAG + booksEP10.getElementsByClass("bookimg").get(0).getElementsByTag("a")
.get(0).attr("href"));
item.setName(booksEP10.getElementsByClass("bookinfo").get(0).getElementsByClass("bookname")
.get(0).getElementsByTag("a").get(0).text());
String kind = booksEP10.getElementsByClass("bookinfo").get(0).getElementsByClass("cat").get(0).text();
kind = kind.replace("分类:", "");
item.setKind(kind);
String author = booksEP10.getElementsByClass("bookinfo").get(0).getElementsByClass("author").get(0).text();
author = author.replace(" ", "").replace(" ", "").replace("作者:", "");
item.setAuthor(author);
item.setLastChapter(booksEP10.getElementsByClass("bookinfo").get(0).getElementsByClass("update")
.get(0).getElementsByTag("a").get(0).text());
item.setDesc(booksEP10.getElementsByClass("bookinfo").get(0).getElementsByTag("p").get(0).text());
books.add(item);
}
emitter.onNext(books);
} else {
emitter.onNext(new ArrayList<SearchBookBean>());
}
} catch (Exception ex) {
ex.printStackTrace();
emitter.onNext(new ArrayList<SearchBookBean>());
}
emitter.onComplete();
}
});
}
我这边主要记录一下,需要源码的我这边推个本地小说源码https://github.com/luoyangGZS/luoluotushu.git
我试着综合了三种类型的,写了一个程序猿自己Android免费小说阅读
安装包链接:https://pan.baidu.com/s/1ooGAhY_dBPwdPoVxSPCStw 提取码:g18k
一起学习交流!创建价值,乐在分享!