图片 32

android 开发框架整合(Rxjava+Retrofit二次封装+dbFlow+rxbus分发事件机制+glide等)

DBFlow,综合了 ActiveAndroid, Schematic, Ollie,Sprinkles
等库的优点。同时不是基于反射,所以性能也是非常高,效率紧跟greenDAO其后。基于注解,使用apt技术,在编译过程中生成操作类,使用方式和ActiveAndroid高度相似,使用简单。

前言:

我们知道rxjava+retrofit+mvp已经出现很久了。由于最近项目需要大整改,故此封装一个比较适用的框架。首先网路框架暂时选用了最新的框架:rxjava+retrofit。至于mvp的话由于之前别人项目写的太过杂乱又经过多人之手,暂时无力修改。当然,封装没有绝对的好与坏,只有适不适合。每个公司有每个公司的规则。

参考了很多网上资料,最终整出了一套属于自己的网络框架。这里特别感谢csdn的大神
wzgiceman  

参考链接:blog.csdn.net/wzgiceman/article/details/52995205

从这篇文献中得到了自己的思路,因为使用retrofit的童鞋大多数都是使用了内置的gson解析,这样有个问题:并不是每个公司的后台都会乖乖地给你返回想要的
jsonObject。就比如我的后台 result如果是集合则返回类似 {“result”
:”[{xxx},{xxx}]”},如果是对象则返回
{“result”:”{xxxxx}”这样想都不用想,不处理直接使用的话肯定会报错。所以修改
.addConverterFactory(GsonConverterFactory.create())–>.addConverterFactory(ScalarsConverterFactory.create())
以string的数据返回。这里有人会问,这样话不是更加不方便了吗?明明人家都帮你解析好了你还多此一举,而且可能只有你公司后台是这样返回的。

这里要说下:其实如果没有这个框架,平常我们使用其他框架,比如xutils等等都是返回json字符串然后手动解析,这样有个好处:更加灵活,扩展性更强。再举个例子:我们的另一个项目返回的格式居然是
“{“status”:”1″}”.
认真看下它是一个字符串(不知道我们后台脑子是不是抽了)。这样不用说同样会报错。其实这里这个例子是为了说明,我们不用使用内置的gson解析,而是拦截得到的数据然后操作成我们想要的数据。换句话说,哪天你和你后台吵架了,人家不帮你改那就尴尬了。

我们看下干货:

封装前:

图片 1

未封装

首先我们可以看到没有封装的框架代码很长,使用方法是配置okhttp,然后用observable去subscribe一个
subscriber
 紧接着就是四个回调。本人是很不喜欢这么多的回调,如果不用mvp模式编写的话那么业务逻辑的代码都要写在activity中,而且这仅仅是一个接口,如果多个接口呢?

同时可以看到其实很多代码是重复多余的。比如okhttp是配置。onCompleted、onStart这两个回调在本人看来也是多余的。其实要用到的onNext(得到数据然后处理)、onError(错误的处理)。

接之前的话题,怎么才能将数据拦截灵活处理呢?
我们可以看到真正得到数据的是onNext
,而之前也说了,回调是在subscriber重写的。那么我们的思路就来了:写一个类继承subscriber然后重写onNext
。得到的数据我们不就可以任意蹂躏了吗?
等到数据处理成自己想要的格式再用一个接口回调返回出去不就好了?

顺着这个思路我们写一个ProgressSubscriber继承Subscriber
 看到类名就想到了我们在访问的同时加一个加载框。而回到中onStart可以做对话框显示的初始化。
onComplete则消除对话框。

图片 2

而onNext则是真正的数据处理

图片 3

再来看下那个接口

图片 4

好了我们的Subscriber就写好了。前文也说了
由于后台的任性返回了不同的结构。不过通过我们的处理之后不管之后返回什么结构都可以解析,我们只要传一个解析的实体类就可以了。真的很方便。

接下来,我们重点用一个例子看看使用过程。

图片 5

依照这个过程

图片 6

两个访问的接口

service有了,我们需要一个retrofit。而我把这些统一写到一个工具类中

图片 7

对象都有了之后只要做subscirbe的操作:

图片 8

我们需要注册一个
subscriber进去。而之前我们已经有了一个progressSubscriber
。同样这个部分的操作我们都在HttpManager封装。

图片 9

基本的操作就好了

我们再看下activity 中具体的调用

图片 10

这是我们的activity中的调用。
onNext中我们通过每个接口中不同的method去区分具体的接口。然后做不同的操作。两个接口仅仅也是写了这些代码而已。

特性:

1、无缝支持多个数据库;
2、使用annotation processing提高速度;
3、ModelContainer类库可以直接解析像JSON这样的数据;
4、增加灵活性的丰富接口。

github仓库:

DBFlow在国内可能用的人不是很多,所以中文介绍很少,所以就有了这篇文章,接下来就让我们一起学习DBFlow。

图片 11

总结:

其实我也是贴了部分重要代码而已。做这个的目的还是为了能够灵活处理返回的数据。主要的思路再说一遍:写一个类继承subscriber并重写onNext
然后得到的数据我们再用一个接口回调。至于之后的那些封装只是为了让代码更加简洁而已,每个人有每个人的习惯和写法,这里不做统一。

最后分享这个框架 接下去还会进行改进以及添加更多的工具:图片处理框架
glide、数据库框架dbflow等等。还是那句话:合适的才是好用的!

百度网盘
链接:http://pan.baidu.com/s/1dFKTDJj
密码:9rk9

github
:github.com/xmrkwzw/rxRetrofit-master

一、引入依赖、初始化

需要引入apt和maven,配置项目的 build.gradle

buildscript {
  repositories {
    jcenter()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:2.0.0-beta6'
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
  }
}

allprojects {
  repositories {
    jcenter()
    maven { url "https://jitpack.io" }
  }
}

配置app的build.gradle

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
def dbflow_version = "3.0.0-beta4"
android {
  compileSdkVersion 23
  buildToolsVersion "23.0.2"

  defaultConfig {
    applicationId "cn.taoweiji.dbflowexample"
    minSdkVersion 14
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
  }
  buildTypes {
    release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }
}

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  apt "com.github.Raizlabs.DBFlow:dbflow-processor:${dbflow_version}"
  compile "com.github.Raizlabs.DBFlow:dbflow-core:${dbflow_version}"
  compile "com.github.Raizlabs.DBFlow:dbflow:${dbflow_version}"
}

需要在Application的onCreate对DBFlow进行初始化

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        FlowManager.init(this);
    }
}

记得修改AndroidManifest.xml

<application
    android:name=".MyApplication"
../>

更新

2017/8/23 :嵌套接口的封装

昨天一个小伙伴突然提了一个疑问:如果一个接口要在另一个接口请求结果的前提下完成(嵌套接口)那要怎么做?

我想都没想

图片 12

那不是可以在onnext里面做完继续做吗? 然后仔细想想
这个是针对单个接口的根据method的条件做if….else的判定。假设第一次请求是
BaseInfoApi.BASE_INFO_METHOD.然后第二次请求是BaseInfoApi.CIVILIZATION_METHOD那么第二次请求完就不会进入第一个的条件了。所以导致第二个的回调没法做。

那么有什么办法可以做嵌套接口的开发呢?
答案是肯定的:我们知道rxjava有很多关键字,其中有一个是flatmap.刚好就是可以做接口的嵌套。

基于这个条件我们在baseApiInfo中又写了一个方法

图片 13

可以看到,我们先调用了
getBaseInfo的一个接口然后用flatmap关键字转化成另一个observable
然后调用了getcivilization的接口。这里需要注意的是func1里面的参数列表。上文我们也说过,我们不再用内置的gson插件而是使用string的方式重新解析。所以这里么的参数列表一定要和接口的service7一致

   public interfaceHttpApiService {

              @GET(“brand/brandBaseInfo”)

               ObservablegetBaseInfo(@Query(“seqNum”) String seqNum);

               @GET(“brand/getMoralRateData”)

               ObservablegetCivilization(@Query(“classId”) String
classId);

  }

然后注册下subscriber.此处我是直接注册了progresssubscriber.这里有个bug暂不知道原因。
 第二个回调应该和上面调用的httpRequest(observable);一样。
这个方法进去实际上做的也是同样的操作,但是不知道为什么回调的始终是第一个接口的结果,可是按道理第一个接口已经在
flatmap转换中的call方法回调了。所以这个问题还有待解决。但是总的来说
嵌套接口已经用flatmap解决了,而且较之其他的方式,这个方式是最好的,代码逻辑也是最合理的。

二、数据库创建、表创建

定义数据库

我这里定义了一个名称叫做AppDatabase的数据库,可以根据自己的喜欢进行定义。

@Database(name = AppDatabase.NAME, version = AppDatabase.VERSION)
public class AppDatabase {
  //数据库名称
  public static final String NAME = "AppDatabase";
  //数据库版本号
  public static final int VERSION = 1;
}

创建数据库对象

必须继承BaseModel,BaseModel包含了基本的数据库操作(save、delete、update、insert、exists),看下面代码可以发现这个表是关联上面定义的数据库,People的id是自增的id。

@ModelContainer
@Table(database = AppDatabase.class)
public class People extends BaseModel {
    //自增ID
    @PrimaryKey(autoincrement = true)
    public Long id;
    @Column
    public String name;
    @Column
    public int gender;
}

编写完数据表对象后,点击Android
studio的build->Make Project(Mac的童鞋直接command+F9)就会使用apt进行了编译,

查看目录(我的people类放在cn.taoweiji.dbflowexample.db)

app/build/generated/source/apt/debug/cn/taoweiji/dbflowexample/db

就可以看到自动生成 People_Adapter、People_Container、People_Table,其中People_Table在后面使用有很大的作用,建议详细看看它的结构。

DBFlow

为什么使用DBFlow:综合了 ActiveAndroid, Schematic, Ollie,Sprinkles
等库的优点。同时不是基于反射,所以性能也是非常高,效率紧跟greenDAO其后。基于注解,使用apt技术,在编译过程中生成操作类,使用方式和ActiveAndroid高度相似,使用简单。

特性:

无缝支持多个数据库;

使用annotation processing提高速度;

ModelContainer类库可以直接解析像JSON这样的数据;

增加灵活性的丰富接口。

使用:

project build.gradle

图片 14

app build.gradle

图片 15

问题:

这里发现了一个问题,假如你的项目中使用了module
而如果将dbflow的依赖添加到
module的build.gradle中就会报初始化错误。所以建议将dbflow依赖写在
app的build.gradle中

Api

使用dbflow的过程其实有遇到很多问题。最大的问题是假如你不翻墙,我们大天朝的百度几乎都是复制来复制去的,没有什么参考的意义。本人在使用的过程遇到了问题通过
stackoverflow一步步查找最终找到了比较好的一个api

agrosner.gitbooks.io/dbflow/content/SQLiteWrapperLanguage.html

三、增删改

由于数据表对象继承了BaseModel,已经包含了很多的操作

People people = new People();
people.name = "Wiki";
people.gender = 1;
people.save();
//people.update();
//people.delete();
Log.e("Test", String.valueOf(people.id));

删除、更新等操作就自己体验,这里就不多说了。

增:insert

图片 16

插入的方式有

1 Model.insert()

如:dbflowModel.insert();

2 SQLite.insert()

图片 17

3插入一个集合

图片 18

使用事务

除了上述方法 当然也可以通过遍历然后通过 model.insert();  
但是如果数据量很大的情况下建议开启事务

四、查询

//返回所有查询结果
List<People> peoples = new Select().from(People.class).queryList();
//返回单个查询结果
People people = new Select().from(People.class).querySingle();
//查询gender = 1的所有People
List<People> peoples2 = new Select().from(People.class).where(People_Table.gender.eq(1)).queryList();

DBFlow的查询方式借鉴ActiveAndroid的,但是比ActiveAndroid功能还要强大。

删 delete

图片 19

其中 使用 Delete.table(Table table)是清空表数据的作用

五、事务、批量保存

事务是一个数据必须具备的,如果保存10000条数据,一条一条保存必然是很慢的,所以就需要用到事务,批量保存。DBFlow的事务非常的强大,同时使用也很复杂,这里就简单介绍批量保存,更多内容请查看官方文档

List<People> peoples = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
    People people = new People();
    people.name = "Wiki";
    people.gender = 1;
    peoples.add(people);
}
//实时保存,马上保存
new SaveModelTransaction<>(ProcessModelInfo.withModels(peoples)).onExecute();
//异步保存,使用异步,如果立刻查询可能无法查到结果
//TransactionManager.getInstance().addTransaction(new SaveModelTransaction<>(ProcessModelInfo.withModels(peoples)));

改 update

图片 20

六、数据库升级(增加表、增加字段等)

如果是新增表无需做特别的处理,直接修改AppDatabase的版本号即可。

如果需要新增字段,除了需要修改AppDatabase的版本号外,还需要做特殊的处理,DBFlow的描述是:Migrations。

例子:对People新增一个email字段

第1步,修改数据库版本号

@Database(name = AppDatabase.NAME, version = AppDatabase.VERSION)
public class AppDatabase {
  //数据库名称
  public static final String NAME = "AppDatabase";
  //数据库版本号,这里修改2
  public static final int VERSION = 2;
}

第2步,需要修改数据表对象结构,增加email

@ModelContainer
@Table(database = AppDatabase.class)
public class People extends BaseModel {
    //自增ID
    @PrimaryKey(autoincrement = true)
    public Long id;
    @Column
    public String name;
    @Column
    public int gender;
    @Column
    public String email;
}

第3步,执行第二步之后,需要build(Android
studio的build->Make Project、Mac的童鞋直接command+F9),通过apt更新People_Table,接下来编写Migrations

@Migration(version = 2, database = AppDatabase.class)
public class Migration_2_People extends AlterTableMigration<People> {

    public Migration_2_People(Class<People> table) {
        super(table);
    }

    @Override
    public void onPreMigrate() {
        addColumn(SQLiteType.TEXT, People_Table.email.getNameAlias().getName());
    }
}

类名可以更加自己喜欢定义,我个人的规则是,按照数据库版本号和需要更新的数据表来命名,需要注意是:version
= 2

数据库升级就大功告成了。

查 query

使用 SQLite.select().from(DBFlowModel.class).querySingle(); 查找一个对象

SQLite.select().from(DBFlowModel.class).queryList(); 查找一个集合对象

同样还有以下api

图片 21

总结

这篇文章只是简单介绍了DBFlow的基本功能使用,DBFlow还有很多很厉害的功能,比如多数据库支持、Powerful
Model Caching等,而且还支持Kotlin语言(运行在Java虚拟机的新语言)。我只使用过greenDAO、activeAndroid、afinal、DBFlow数据库,所以在我看来,DBFlow是我用过的数据库当中最好用的数据库,性能也很好,使用非常简单,高度推荐。

我在github上共享一下DBFlow的配置:

事务

事务是一个数据必须具备的,如果保存10000条数据,一条一条保存必然是很慢的,所以就需要用到事务,批量保存。DBFlow的事务非常的强大,同时使用也很复杂;

查询

图片 22

保存

图片 23

如果是新增表无需做特别的处理,直接修改AppDatabase的版本号即可。

如果需要新增字段,除了需要修改AppDatabase的版本号外,还需要做特殊的处理,DBFlow的描述是:Migrations。

例子:对People新增一个email字段

第1步,修改数据库版本号

图片 24

第2步,需要修改数据表对象结构,增加email

图片 25

第3步,执行第二步之后,需要build(Android
studio的build->Make Project、Mac的童鞋直接command+F9),通过apt更新People_Table,接下来编写Migrations

图片 26

类名可以更加自己喜欢定义,我个人的规则是,按照数据库版本号和需要更新的数据表来命名,需要注意是:version
= 2

数据库升级就大功告成了。

基本的使用就这些,其他api用法请往这边看 https://agrosner.gitbooks.io/dbflow/content/SQLiteWrapperLanguage.html

Rxbus

它不是一个库,而是一个文件,最短实现只有短短30行代码。RxBus本身不需要过多分析,它的强大完全来自于它基于的RxJava技术。响应式编程(Reactive
Programming)技术这几年特别火,RxJava是它在Java上的实作。RxJava天生就是类似sub/pub的观察者模式,而且很容易处理线程切换

rxbus并没有一个统一的标准,他是一种概念。如果要看概念的,网上也是有很多资料。这里不做详解

在用过rxjava前相信很多人使用过eventbus 

如果你的项目中已经开始使用EventBus,没有必要特意换用RxBus。

如果你的项目计划引入RxJava,并认为统一风格很重要,启用RxBus,抛弃EventBus没有问题。但是请了解RxBus的问题,并关注RxBus的进展,最好能用Rx的方式解决这个问题。

使用:

推荐一个不错的rxbus github.com/xmrkwzw/Rxbus-1 如果只是做单独的post发送消息网上有很多资源。而就发送粘性事件(stickyEvent)
我觉得这个封装的很不错。

用法 :

订阅者

图片 27

注册与反注册

图片 28

粘性事件接收,注解中一定要记得加上sticky = true

发送者

图片 29

glide

glide相信很多人都在用。而这次用到的是glide4.0 同时支持kotlin。

glide4.0在用法上和之前确实有不小的改变。新增的API(RequestBuilder,RequestOptions)

具体的用法可以到官网查看api 

bumptech.github.io/glide/

或者查看某作者的整合博客

blog.csdn.net/github_33304260/article/details/72526237

这里只贴出部分功能的代码

图片 30

一般设置

图片 31

图片 32

可以看出官方把有些方法都集成到了上述的两个api中。具体的其他方法请看官网介绍。

以上框架就基本搭建好了,如有什么不足和bug,欢迎提出意见和建议。

发表评论

电子邮件地址不会被公开。 必填项已用*标注