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) "; }
这三张表示基础表。和数据缓存有关系。