以前一直使用自己开发的Android(java版本)框架,使用起来非常方便,如
class
这是我改成kotlin后的版本,使用起来非常方便,只要指定泛型就行了,不用再手动去new Fragment。但这样做也有不足,因为是通过反射来获取类名的,而java的泛型还是有很多不足的。反射代码如下:
open
我们希望统一的代码写在统一的基类里面,所以就必须写在BaseActivityWithFragment里面,但是这时就无法通过V来获取真实的类型,必须通过其他方式(以上方式)转折获取。当然有时还会遇到再上一级父类想使用泛型的情况,那就更加无能为力了(这就是Java系的弊病,Kotlin在这一方面保留了这个毛病)。而我一直就突破,想改进,终于通过前面学习后了解到了Koin(主要优点是不用反射)。这次我想尝试一下能不能不用反射,又能最简单的完成以上的功能的全新框架。
因为以前的框架为了简单使用了Databinding,确实方便了许多,当然,我也想只通过泛型配置一下就可以反射生成ViewDatabing,最终也实现了,当前问题也是一样反射会有各种性能问题。这一次编写框架我仍然是顺手添加了Databinding,后来发现有很多问题,一点优势没体现出来, 因为有kotlin-android-extensions。所以后来我就去掉了这个功能。
1、简要说明
我希望将程序分为动静两部分。举例说明分页加载弹出进度条的功能,我们可以按命令模式提取几个大步骤:
1、显示加载进度
2、加载数据
3、加载完成显示数据,关闭进度对话框
4、错误处理
我们就可以将这些基本步骤写在父类中(这是静的部分),而加载数据必须是动的(每个页面必须不同)、显示数据也一定是动的。为了更简单的动的部分,我们可不可以只用处理加载数据(可以是网络,也可以是数据库)最原始的部分,而显示以RecycleView为例我们应该只要用户处理一下ViewHolder就结束为好。这也就是我要编写框架的初衷,当然以Java为语言的版本我都做过多次尝试,包括前言所说的反射,已经完成了一套非常实用的框架。我还编写过使用c#编写的动态生成基础页面的可以直接运行的小程序,大大提高了开发效率,最主要的是保证了不会出错,当然出现错误也可以只用修改一处。那么,怎样封装怎么简化就是我要考虑的问题。当然最先要考虑怎样实现,而每一个框架都是迭代的过程,我也会将整个代码迭代重构的过程详细记录以供大家参考。同时会将源码提供大学一起学习,有问题可以和我沟通交流。
2、参照源码
参照源码github地址: kudago-kotlin
Kotlin, MVVM, AndroidX, Paging, Network (Coroutines+Retrofit2+OkHttp3+Gson), Glide, Maps
这个源码大家可以自己学习,也可以按我以前写的《Kotlin学习之开源代码分析、重构》两篇文章中提到的方法进行学习。
kudago使用的是dagger而不是koin,还使用了realm-gradle-plugin(我还没涉入,连名称都不知),所以我只是使用里面的数据源,以及分页加载部分,提取公用类库。我也是按照前面写的方法只迁移了主界面,分页数据加载,显示等功能。由于这一部分以前写过,所以提取框架是在迁移后的基础上进行的。
3、框架代码
框架代码github地址: KivyV1.0.3
3.1 新建项目
这个前面也提到过,不过要新建xframework类库将一些通用的东西都放在类库里。
补充说明一点,考虑到要使用沉浸式状态栏 ImmersionBar ,所以尽可能的使用Fragment来显示(这是我这样使用而非 ImmersionBar 强烈建议)。
android 4.4以上沉浸式状态栏和沉浸式导航栏管理,适配横竖屏切换、刘海屏、软键盘弹出等问题,可以修改状态栏字体颜色和导航栏图标颜色,以及不可修改字体颜色手机的适配,适用于Activity、Fragment、DialogFragment、Dialog,PopupWindow,一句代码轻松实现,以及对bar的其他设置,详见README。简书请参考: http://www. jianshu.com/p/2a884e211 a62
通过分析kudago代码后,对分页显示比以前的Fragment多了一个DiffUtil类,我的目标是只要是分页加载,也就只要编写这五个类就可以了其他的代码尽量少写。
五个类分别为:DiffUtil,Adapter,Fragment,ViewHolder,ViewModel等。所以我也就必须要编写这五个类的基类,能写在基类的就一定要定在基类里。
3.1.1 xframework的包结构
1、exception存放自定义的异常
2、ext存放要使用到的一些扩展方法
3、tools现在存放了XLiveDataBus以及XImmersionBar相关的类
4、utils存放一些常用的Utils,暂时放的日夜模式相关的代码
5、mvvm存放了mvvm相关的代码
6、ui提供了一些ui相关的基础类,主要是BaseActivity和BaseFragment相关的类,前面也说过尽可能将相关的代码写在Fragment中
3.2 UI
3.2.1 BaseActivity
BaseActivity主要是样式主题切换,导出时关掉当前activity等功能。
open
3.2.2 BaseFragment
BaseFragment除了使用 ImmersionBar相关代码外,只是增加了一个钩子函数,没有其他用途。主要是统一使用BaseFragment后如果要增删功能时方便。
abstract
3.2.3 BaseActivityWithFragment
这个类比较简单,只是将Fragment嵌入到Activity中,现在的主要问题前面就说过创建Fragment的问题。在不是非常熟悉的情况下,我先考虑new的方式,以后可以考虑其他方式。
xml代码:
<?xml version="1.0" encoding="utf-8"?>
其中注释的代码是通过反射生成Fragment的方式,现在想的是通用不能不用反射,而是考虑使用koin。
3.2.4 BaseFragmentBingToolBar
这里要说明一下命令规则,这中间增加了Bing本来是准备使用databiding的,然后去掉了,这个名称没有修改过来大家可以忽略,以后也会进行修改过来。因此此类主要功能是处理ToolBar的。
abstract
3.2.5 BasePagingRecycleFragment
这是我们的重头戏,所有分页显示代码都在这里。先看源码:
布局xml相对比较简单:
<?xml version="1.0" encoding="utf-8"?>
abstract
通过泛型T,A,VM引入实体类型,Adapter和ViewModel,具体实现也就比较简单了。
3.3 MVVM
现在开始逐一讲解一下前面说的adapter和viewmodel,还有一些辅助类。mvvm根据具体的用途分文件夹。
3.3.1 IRecycleViewCallback
这个可能名字有点问题,不过主要是针对RecycleView的Item的单击和长按事件的回调方法。
/**
3.3.2 viewmodel
此包名下,有两个ViewModel,主要是因为现在以分页为主,必须预留公用类,供不分页的viewmodel使用。
abstract
分页的BasePagingViewModel就比较麻烦,这个主要是参照kudago进行编写,暂时可以理解为非要这么用,更多详细只能参照以后重构。
abstract
这里的PAGE_SIZE本来是常量,不过我进行修改了有的地方可能会一次加载20条,kudago就是20。
这里使用到IPagingRepository和PagingDataSource。
3.3.3 IPagingRepository
interface
这是个接口,暂时只是传入分页和页码,同时对page还有两种类型Int和String要指定。这里的函数名getEvents有机会也要修改一下。
3.3.4 PagingDataSource
abstract
父类PageKeyedDataSource要指定id类型,要加载两次数据,初始数据以及加载下一页数据,为了通用我增加了getNext抽象函数,可以继承后具体实现。
同时指定返回类型PagingResult放在data目录下
data
3.3.5 BasePagingAdapter
分页的Adapter要继承自PagedListAdapter,查看要指定的泛型和接收的参数,也必须通过BasePagingAdapter传递出去。
这里使用到viewholder,下面将看一下viewholder
3.3.6 viewholder
统一实现数据绑定IViewHolderBind
interface
ViewHolder的实现比较简单
事件也通过init放进来了。
到此为止,基本上能使用到的功能都一一介绍过。
3.4 实现代码
kivyv103的app代码按照以前惯例仍然是分为data、di、ui、utils等目录。
3.4.1 数据部分
3.4.1 domain
这个相对简单,针对 kudago少了外面一层的Events(这个对应的类是xframework中的PagingResult)
data
3.4.2 repository
EventRepository是继承IPagingRepository接口
class
IService相关的就不详细说明了。
分页数据源代码:
class
这里只是将前面注释的代码直接显示在getNext方法里。
3.4.3 ui
3.4.3.1 MainActivity
前面说过要尽可能使用Fragment来实现具体业务,所以要使用BaseActivityWithFragment类,尽可能不使用反射就只能通过inject注入。
class
3.4.3.2 MainFragment 相关
五个相关类
1、EventsDiffUtil
用于比较两个Event
class
2、MainViewHolder
因为kotlin-android-extensions,所以databinding也就没有太多优势。
class
3、MainAdapter
暂时也不动态创建MainViewHolder,直接new了
class
现在的adapter只处理一种类型,多种类型的看重构吧。
4、MainViewModel
这个非常简单,生成对应的EventPagingDataSource就可以了
class
5、MainFragment
继承BasePagingRecycleFragment后,只要override一些创建方法就结束了。后面可以考虑不手动new,而是通过koin进行。暂时还是直接new。
class
3.5 di
现在的所有问题基本上都统一到了di部分。
同理初始化Application代码不可少。
class
3.5.1 remote_datasource
这里的代码配置过多次,唯一要注意的是JSON的问题
val
remote_datasource
val
3.5.2 正常的modules
都是一些前面讲过的常规配置,主要是保证代码能运行,功能能完成。更多的优化只能在优化部分。
val
4、总结
真正调试代码也不可能像以上那样一帆风顺,以上的罗列都是经过不断尝试的结果。主要是一种思路,怎样迁移别人的源码同时内化为自己代码的过程。
5、问题
adapter 能不能注入,viewholder能不能注入等。问题不断,优化不断。
源码:
github: KivyV1.0.3 框架可运行代码release版本。
![e3c333ef59ba7e31a9f31cc63f3a972e.png](https://i-blog.csdnimg.cn/blog_migrate/290bb41e38bd0c4b02d7bbbf1c90f17c.jpeg)