栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

基于rxjava实现的小说练习项目

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于rxjava实现的小说练习项目

基于rxjava实现的小说练习项目
  • 界面展示
    • 目录界面
    • 章节界面
  • 使用框架
  • 使用技术
  • 代码展示
  • 项目详解
    • 添加依赖
    • 根据逻辑划分包
    • 实现logic逻辑层
      • 判断可行性
        • 爬取链接
        • 链接数据
    • 实现Model层
      • Chapter
      • Novel
    • 实现网络请求层
      • ConstantUtils
      • Okhttp实现网络请求
        • ClientUtils
        • OkhttpUtils
        • RxjavaUtils
        • MainViewModel
    • UI层后续

界面展示 目录界面

章节界面

使用框架

room访问数据库
navigation界面导航
okhttp网络请求
viewmodel管理数据
jsoup网络爬虫
rxjava线程优雅

使用技术

stream优雅处理流

代码展示

github: https://github.com/15029291643/novel2

项目详解 添加依赖
// room
def room_version = "2.4.2"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// optional - RxJava2 support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// rxjava
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.9'
// retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.2'
// jsoup
implementation 'org.jsoup:jsoup:1.13.1'
// Navigation
implementation "androidx.navigation:navigation-fragment:2.3.5"
implementation "androidx.navigation:navigation-ui:2.3.5"
根据逻辑划分包

实现logic逻辑层 判断可行性 爬取链接

目录:蛇王诅咒:妈咪要下蛋
章节:解剖双头蛇王

链接数据

目录界面F12进入

可以从页面源代码中直接获取到对应章节1的标题3和链接2
章节界面F12进入

可以很轻松的在源代码中找到章节13对应的标题2和内容4
显而易见,数据可以轻松得到,只要我们拥有一个Jsoup爬虫框架
在这之前先生成两个数据类

实现Model层

Chapter
import java.util.List;

public class Chapter {
    private String title;
    private String url;
    private List content;

    public Chapter() {
    }

    public Chapter(String title, String url) {
        this.title = title;
        this.url = url;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public List getContent() {
        return content;
    }

    public void setContent(List content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "Chapter{" +
                "title='" + title + ''' +
                ", url='" + url + ''' +
                ", content=" + content +
                '}';
    }
}

Novel
import java.util.List;

public class Novel {
    private String title;
    private String url;
    private List catalog;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public List getCatalog() {
        return catalog;
    }

    public void setCatalog(List catalog) {
        this.catalog = catalog;
    }

    @Override
    public String toString() {
        return "Novel{" +
                "title='" + title + ''' +
                ", url='" + url + ''' +
                ", catalog=" + catalog +
                '}';
    }
}

实现网络请求层

ConstantUtils
public interface ConstantUtils {
    String NOVEL_URL = "https://www.258xswz.com/l/6791.html";
    String CHAPTER_URL = "https://www.258xswz.com/y/6791-2976071.html";
    String BASE_URL = "https://www.258xswz.com/";
}

import com.example.rxjava.logic.model.Chapter;
import com.example.rxjava.logic.model.Novel;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;


public class JsoupUtils {
    private static final String TAG = "JsoupUtils";

    // 从html中获取Novel对象
    public static Novel getNovel(String html) {
        // 使用xpath解析数据
        Document parse = Jsoup.parse(html);
        String title = parse.selectFirst("body > div.chapterlist > h2 > strong").text();
        Elements elements = parse.select("#myarticle > table > tbody > tr > td > a");
        // 使用流完成对象转换
        List catalog = elements.stream().map(element ->
                new Chapter(element.text(),
                        ConstantUtils.BASE_URL + element.attr("href")))
                .collect(Collectors.toList());
        Novel novel = new Novel();
        novel.setTitle(title);
        novel.setCatalog(catalog);
        return novel;
    }
    
    // 从html中获取Novel对象
    public static Chapter getChapter(String html) {
        // 使用xpath解析数据
        Document parse = Jsoup.parse(html);
        String title = parse.selectFirst("#title").text();
        String content = parse.select("body > div.chapterlist > div.Readarea").text();
        // 解析后是一个字符串,用split进行分割
        ArrayList content2 = new ArrayList<>(Arrays.asList(content.split(" ")));
        Chapter chapter = new Chapter();
        chapter.setTitle(title);
        chapter.setContent(content2);
        return chapter;
    }
}

Okhttp实现网络请求 ClientUtils
import okhttp3.OkHttpClient;

public class ClientUtils {
    private static volatile OkHttpClient sInstance;

    public static OkHttpClient getInstance() {
        if (sInstance == null) {
            synchronized (ClientUtils.class) {
                if (sInstance == null) {
                    sInstance = new OkHttpClient();
                }
            }
        }
        return sInstance;
    }
}
OkhttpUtils
import com.example.rxjava.logic.model.Chapter;
import com.example.rxjava.logic.model.Novel;

import java.io.IOException;

import okhttp3.Request;
import okhttp3.Response;


public class OkhttpUtils {
    private static String getHtml(String url) {
        Request request = new Request.Builder().url(url).build();
        try {
            Response response = ClientUtils.getInstance().newCall(request).execute();
            return new String(response.body().bytes(), "gbk");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Novel getNovel(String url) {
        Novel novel = JsoupUtils.getNovel(getHtml(url));
        novel.setUrl(url);
        return novel;
    }

    public static Chapter getChapter(String url) {
        Chapter chapter = JsoupUtils.getChapter(getHtml(url));
        chapter.setUrl(url);
        return chapter;
    }
}
RxjavaUtils
import android.annotation.SuppressLint;

import com.example.rxjava.logic.model.Chapter;
import com.example.rxjava.logic.model.Novel;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;


public class RxjavaUtils {
    @SuppressLint("CheckResult")
    public static Flowable getNovel(String url) {
        return Flowable.create(emitter ->
                emitter.onNext(OkhttpUtils.getNovel(url)), BackpressureStrategy.ERROR);
    }

    public static Flowable getChapter(String url) {
        return Flowable.create(emitter ->
                emitter.onNext(OkhttpUtils.getChapter(url)), BackpressureStrategy.ERROR);
    }
}
MainViewModel
import android.annotation.SuppressLint;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;

import com.example.rxjava.logic.model.Chapter;
import com.example.rxjava.logic.model.Novel;
import com.example.rxjava.logic.network.OkhttpUtils;
import com.example.rxjava.logic.network.RxjavaUtils;

import java.util.function.Function;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;

public class MainViewModel extends ViewModel {
    private final CompositeDisposable mDisposable = new CompositeDisposable();
    private final MutableLiveData mNovel = new MutableLiveData<>();
    private final MutableLiveData mChapter = new MutableLiveData<>();
    private final MutableLiveData mPosition = new MutableLiveData<>(0);
    private final LiveData mTitle = Transformations.map(mChapter, chapter ->
            "第" + (mPosition.getValue() + 1) + "章 " + chapter.getTitle());
    private final LiveData mContent = Transformations.map(mChapter, input ->
            input.getContent()
                    .stream()
                    .reduce("        ", (s1, s2) -> s1 + "nn" + "        " + s2));

    public MutableLiveData getNovel() {
        return mNovel;
    }

    public LiveData getTitle() {
        return mTitle;
    }

    public void setPosition(int position) {
        mPosition.setValue(position);
        setChapter(mNovel.getValue().getCatalog().get(position).getUrl());
    }

    public void toNext() {
        if (mPosition.getValue() != mNovel.getValue().getCatalog().size() - 1) {
            setPosition(mPosition.getValue() + 1);
        }
    }

    public LiveData getContent() {
        return mContent;
    }

    public void setNovel(String url) {
        mDisposable.add(RxjavaUtils.getNovel(url)
                .subscribeOn(Schedulers.io())
                .subscribe(mNovel::postValue));
    }

    private void setChapter(String url) {
        mDisposable.add(RxjavaUtils.getChapter(url)
                .subscribeOn(Schedulers.io())
                .subscribe(mChapter::postValue));
    }
}

基于此,所有数据层面已经全部完成,但其中应用框架部分还没讲,等先把那部分更新完后先继续讲

UI层后续

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/937716.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号