TouTiao开源项目 分析笔记5
1.深入理解RxJava
1.1.基本上现在的APP都会有请求网络,然后处理回调的业务吧。
如果请求的数据很多,业务越来越复杂,怎么处理呢?
这里我用到了RxJava来帮我处理业务。
RxJava主要复杂事件的通知和订阅。这个挺起来没有什么概念。
其实说白了,RxJava就是优雅地处理函数回调。
这篇文章以一个案例的方式,详细解释了rxjava的功能。
下面我来深入分析一下。
1.3.以通常思维模式来处理这个案例。

这个比较好理解,但是这种方式不是异步请求。现在网络请求基本都要异步线程调用。
1.4.那么修改一下实现方式。

1.5.有匿名类,然后消除

这里将Callback<T>封装起来为一个Task<T>任务了。
1.6.处理逻辑层

1.7.定义一个抽象类AbstractTask<T> 来实现Task<T>

1.8.最终业务层

2.自定义RxBus
2.1.参考文章:Android RxJava实现RxBus。
源代码:
package com.meiji.toutiao; import android.support.annotation.NonNull; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import io.reactivex.Observable;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject; /**
* https://juejin.im/entry/58ff2e26a0bb9f0065d2c5f2
*/ public class RxBus { private ConcurrentHashMap<Object, List<Subject>> subjectMapper =
new ConcurrentHashMap<>(); private RxBus() { } private static class Holder {
private static RxBus instance = new RxBus();
} @NonNull
public static RxBus getInstance() {
return Holder.instance;
} @NonNull
public <T> Observable<T> register(@NonNull Class<T> clz) {
return register(clz.getName());
} @NonNull
public <T> Observable<T> register(@NonNull Object tag) {
List<Subject> subjectList = subjectMapper.get(tag);
if (null == subjectList) {
subjectList = new ArrayList<>();
subjectMapper.put(tag, subjectList);
} Subject<T> subject = PublishSubject.create();
subjectList.add(subject); //System.out.println("注册到rxbus");
return subject;
} public <T> void unregister(@NonNull Class<T> clz, @NonNull Observable observable) {
unregister(clz.getName(), observable);
} public void unregister(@NonNull Object tag, @NonNull Observable observable) {
List<Subject> subjects = subjectMapper.get(tag);
if (null != subjects) {
subjects.remove(observable);
if (subjects.isEmpty()) {
subjectMapper.remove(tag);
//System.out.println("从rxbus取消注册");
}
}
} public void post(@NonNull Object content) {
post(content.getClass().getName(), content);
} public void post(@NonNull Object tag, @NonNull Object content) {
List<Subject> subjects = subjectMapper.get(tag);
if (!subjects.isEmpty()) {
for (Subject subject : subjects) {
subject.onNext(content);
}
}
} }
2.2.定义一个ConcurrentHashMap。
顾名思义,类似于HashMap,用来临时存储数据的。而且处理了一些多线程安全之类的东西。
private ConcurrentHashMap<Object, List<Subject>> subjectMapper =
new ConcurrentHashMap<>();
2.3.然后是新建一个实例
private RxBus() {}
private static class Holder {
private static RxBus instance = new RxBus();
}
@NonNull
public static RxBus getInstance() {
return Holder.instance;
}
2.4. 注册的两个方法
@NonNull
public <T> Observable<T> register(@NonNull Class<T> clz) {
return register(clz.getName());
} @NonNull
public <T> Observable<T> register(@NonNull Object tag) {
List<Subject> subjectList = subjectMapper.get(tag);
if (null == subjectList) {
subjectList = new ArrayList<>();
subjectMapper.put(tag, subjectList);
} Subject<T> subject = PublishSubject.create();
subjectList.add(subject); //System.out.println("注册到rxbus");
return subject;
}
传入一个Class<T>参数
或传入一个Object 参数
返回一个Observable<T>类型数据
这里返回一个Subject<T>类型数据
2.5.反注册的两个方法
public <T> void unregister(@NonNull Class<T> clz, @NonNull Observable observable) {
unregister(clz.getName(), observable);
}
public void unregister(@NonNull Object tag, @NonNull Observable observable) {
List<Subject> subjects = subjectMapper.get(tag);
if (null != subjects) {
subjects.remove(observable);
if (subjects.isEmpty()) {
subjectMapper.remove(tag);
//System.out.println("从rxbus取消注册");
}
}
}
传入两个参数:Class<T> clz,Observable observable
或传入两个参数:Object tag,Observable obervable
调用subjectMapper的remove(tag)方法来取消注册。
2.6.两个post方法
public void post(@NonNull Object content) {
post(content.getClass().getName(), content);
}
public void post(@NonNull Object tag, @NonNull Object content) {
List<Subject> subjects = subjectMapper.get(tag);
if (!subjects.isEmpty()) {
for (Subject subject : subjects) {
subject.onNext(content);
}
}
}
传入一个参数Object content
或传入两个参数:Object tag,Object Content
调用subject.onNext(content)来post。
不返回数据。
3.DatabaseHelper帮助器
3.1.源代码
package com.jasonjan.headnews.database.helper; import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import com.jasonjan.headnews.database.table.MediaChannelTable;
import com.jasonjan.headnews.database.table.NewsChannelTable;
import com.jasonjan.headnews.database.table.SearchHistoryTable;
import com.jasonjan.headnews.global.InitApp; /**
* Created by JasonJan on 2017/12/4.
*/ public class DatabaseHelper extends SQLiteOpenHelper{ private static final String DB_NAME = "Toutiao";
private static final int DB_VERSION = 5;
private static final String CLEAR_TABLE_DATA = "delete from ";
private static final String DROP_TABLE = "drop table if exists ";
private static DatabaseHelper instance = null;
private static SQLiteDatabase db = null; private DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
} private static synchronized DatabaseHelper getInstance() {
if (instance == null) {
instance = new DatabaseHelper(InitApp.AppContext, DB_NAME, null, DB_VERSION);
}
return instance;
} public static synchronized SQLiteDatabase getDatabase() {
if (db == null) {
db = getInstance().getWritableDatabase();
}
return db;
} public static synchronized void closeDatabase() {
if (db != null) {
db.close();
}
} @Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(NewsChannelTable.CREATE_TABLE);
db.execSQL(MediaChannelTable.CREATE_TABLE);
db.execSQL(SearchHistoryTable.CREATE_TABLE);
} @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL(MediaChannelTable.CREATE_TABLE);
break;
case 2:
db.execSQL(CLEAR_TABLE_DATA + NewsChannelTable.TABLENAME);
break;
case 3:
ContentValues values = new ContentValues();
values.put(NewsChannelTable.ID, "");
values.put(NewsChannelTable.NAME, "推荐");
values.put(NewsChannelTable.IS_ENABLE, 0);
values.put(NewsChannelTable.POSITION, 46);
db.insert(NewsChannelTable.TABLENAME, null, values);
break;
case 4:
db.execSQL(SearchHistoryTable.CREATE_TABLE);
break;
}
}
}
synchronized关键字:加了同步锁,保证线程同步。
4.三张原始表
4.1.NewsChannelTable
public class NewsChannelTable {
/**
* 新闻频道信息表
*/
public static final String TABLENAME = "NewsChannelTable";
/**
* 字段部分
*/
public static final String ID = "id";
public static final String NAME = "name";
public static final String IS_ENABLE = "isEnable";
public static final String POSITION = "position";
/**
* 字段ID 数据库操作建立字段对应关系 从0开始
*/
public static final int ID_ID = 0;
public static final int ID_NAME = 1;
public static final int ID_ISENABLE = 2;
public static final int ID_POSITION = 3;
/**
* 创建表
*/
public static final String CREATE_TABLE = "create table if not exists " + TABLENAME + "(" +
ID + " text primary key, " +
NAME + " text, " +
IS_ENABLE + " text default '1', " +
POSITION + " text) ";
}
4.2.MediaChannelTable
public class MediaChannelTable {
/**
* 头条号信息表
*/
public static final String TABLENAME = "MediaChannelTable";
/**
* 字段部分
*/
public static final String ID = "id";
public static final String NAME = "name";
public static final String AVATAR = "avatar";
public static final String TYPE = "type";
public static final String FOLLOWCOUNT = "followCount";
public static final String DESCTEXT = "descText";
public static final String URL = "url";
/**
* 字段ID 数据库操作建立字段对应关系 从0开始
*/
public static final int ID_ID = 0;
public static final int ID_NAME = 1;
public static final int ID_AVATAR = 2;
public static final int ID_TYPE = 3;
public static final int ID_FOLLOWCOUNT = 4;
public static final int ID_DESCTEXT = 5;
public static final int ID_URL = 6;
/**
* 创建表
*/
public static final String CREATE_TABLE = "create table if not exists " + TABLENAME + "(" +
ID + " text primary key, " +
NAME + " text, " +
AVATAR + " text, " +
TYPE + " text, " +
FOLLOWCOUNT + " text, " +
DESCTEXT + " text, " +
URL + " text) ";
}
4.3.SearchHistoryTable
public class SearchHistoryTable {
/**
* 浏览记录表
*/
public static final String TABLENAME = "SearchHistoryTable";
/**
* 字段部分
*/
public static final String ID = "id";
public static final String KEYWORD = "keyWord";
public static final String TIME = "time";
/**
* 字段ID 数据库操作建立字段对应关系 从0开始
*/
public static final int ID_ID = 0;
public static final int ID_KEYWORD = 1;
public static final int ID_TIME = 2;
/**
* 创建表
*/
public static final String CREATE_TABLE = "create table if not exists " + TABLENAME + "(" +
ID + " text auto_increment, " +
KEYWORD + " text primary key, " +
TIME + " text) ";
}
这三张表示基础表。和数据缓存有关系。
TouTiao开源项目 分析笔记5的更多相关文章
- TouTiao开源项目 分析笔记2
1.Constant常量定义类 1.1.源代码 public class Constant { public static final String USER_AGENT_MOBILE = " ...
- TouTiao开源项目 分析笔记6
1.NewsChannelBean简单类笔记 1.1.Comparable接口的实现和使用 参考文章:Comparable接口的实现和使用. 因为NewsChannelBean实现了Comparabl ...
- TouTiao开源项目 分析笔记4==>一个简单APP 整体常用框架
1.效果预览 1.1.如下图所以,到目前为止所有的功能. 2.从InitApp开始->SplashActivity->MainActivity 2.1.InitApp源代码.这是整个项目的 ...
- TouTiao开源项目 分析笔记15 新闻详情之两种类型的实现
1.预览效果 1.1.首先看一下需要实现的效果. 第一种,文字类型新闻. 第二种,图片类型新闻. 1.2.在NewsArticleTextViewBinder中设置了点击事件 RxView.click ...
- TouTiao开源项目 分析笔记12 从总体到局部 构建视频主页面
1.构建视频主列表的整体碎片VideoTabLayout 1.1.首先创建一个VideoTabLayout package com.jasonjan.headnews.module.video; im ...
- TouTiao开源项目 分析笔记10 实现通用普通文章片段页面
1.RxJava的Observable数据操作符总结 1.1.Map操作符 Map操作符对原始Observable发射的没一项数据应用一个你选择的函数, 然后返回一个发射这些结果的Observable ...
- TouTiao开源项目 分析笔记1
1.InitApp==>项目的入口Application 1.1.继承了MultiDexApplication 超过65K方法的APP,会遇到65535的错误.原因就是为了支持比较大型的APP而 ...
- TouTiao开源项目 分析笔记18 视频详情页面
1.效果预览 1.1.需要做到的真实效果 1.2.触发的点击事件 在MediaArticleVideoViewBinder的每一个item点击事件中: VideoContentActivity.lau ...
- TouTiao开源项目 分析笔记17 新闻媒体专栏
1.效果预览 1.1.要实现的效果 1.2.如何调转到新闻媒体专栏 点击右上角的用户图标. 在新闻详情页面的Fragment的菜单点击事件中触发. case R.id.action_open_medi ...
- TouTiao开源项目 分析笔记16 新闻评论
1.要达到的效果 1.1.主要效果图 点击了标题栏的消息图标后,然后会跳转到评论详情的页面. 1.2.触发的点击事件 在新闻详情的片段中的菜单点击事件中 设置上方标题栏的消息标的监听事件 case R ...
随机推荐
- Web前端开发规范(一)
1.前言 网页开发技术从1989年开始至今已经走过了20余年,从最初纯粹的学术交流,到门户网站.电子商务网站.博客.E-mail.Web游戏.SNS网站等,以及到如今的移动Web网站(其实可以认为是P ...
- Java 开发小常识
从理论上来讲Java做的系统并不比其他语言开发出来的系统更占用内存,那么为什么却有这么多理由来证明它确实占内存呢?两个字,陋习. 1.别用new Boolean().在很多场景中Boolean类型是必 ...
- python+pywinauto之PC端自动化一
所需软件安装: 1.下载 pywinauto 安装参考: https://jingyan.baidu.com/article/414eccf6a1a3906b421f0a59.html 下载地址: h ...
- winxp如何开启SNMP服务
1.先安装SNMP组件 开始——> 控制面板——>添加或删除程序——>添加/删除windows组件——>管理和监视工具(前面方框选择后)——>详细信息——>简 ...
- 基于FPGA的VGA显示设计(二)
上一篇:基于FPGA的VGA显示设计(一) 参照 CrazyBingo 的 基于FPGA的VGA可移植模块终极设计代码 的工程代码风格,模块化处理了上一篇的代码,并增加了一点其它图形. 顶层 ...
- vm中efi模式安装windows10
选择dvd: 界面出现“Press any key to boot from CD or DVD”时,再迅速按下任意键就OK了.
- avast从隔离区恢复后,仍无法打开被误杀文件的解决方案
从隔离区中手动恢复后,隔离区中被恢复的文件将不再展示. 此时,如果手动恢复的文件仍无法打开(图标此时也异常),请: 将avast禁用: 将avast启用. 然后尝试重新打开被误隔离并手动恢复的文件.
- 缓存的set、getAndTouch一定要谨慎使用
缓存的set.getAndTouch一定要谨慎使用. 很多人认为缓存在内存中性能良好,频繁更新,却不想机器的IO无法支撑,结果就是缓存成了系统的瓶颈.
- 【js基础修炼之路】- 微任务,宏任务和Event-Loop
一段代码让你了解Event-Loop console.log(1); setTimeout(() => { console.log(2); }, 0); new Promise((resolve ...
- 【JavaScript 封装库】BETA 1.0 测试版发布!
/* 源码作者: 石不易(Louis Shi) 联系方式: http://www.shibuyi.net =============================================== ...