Android 使用kotlin+注解+反射+泛型实现MVP架构

一,MVP模式的定义

①Model:用于存储数据。它负责处理领域逻辑以及与数据库或网络层的通信。

②View:UI层,提供数据可视化界面,并跟踪用户的操作,以便通知presenter。

③Presenter:从Model层获取数据,并且应用UI逻辑来决定显示什么。它管理View的状态,并且根据来自于View的用户的输入执行动作。

实现mvp模式的核心点就是将view层和presenter绑定,将view层和model层解耦

二,代码实现

首先,我们先三个基本的接口:

/**
*View层接口
*/
interface IView {fun getContext(): Context?fun getRootViews(): View?fun <T : View?> getView(id: Int): Tfun getActivity(): Activity?fun getFragment(): Fragment?
}
/*** module层接口* */
interface IModule {
}
/*** Presenter层接口* */
interface IPresenter {fun onCreate(savedInstanceState: Bundle?, mContext: Context?)fun onResume()fun onStart()fun onRestart()fun onPause()fun onStop()fun onDestroy()fun onSaveInstanceState(outState: Bundle)fun onRestoreInstanceState(savedInstanceState :Bundle)fun onActivityResult( requestCode :Int, resultCode :Int, data : Intent)}

View层主要是获取Activity,布局文件等操作

Presenter层主要是控制Activity生命周期等

Module层就是用户根据自己的业务逻辑具体的自己去定义

接下来我们就利用反射+注解,在系统启动activity的时候,自动的生成相应的presenter实例,这样就不用手动去绑定view和presenter了

创建一个注解:

@Retention(AnnotationRetention.RUNTIME)
annotation class Request(val value:KClass<*>)

在运行时生效,传入kotlin的Class实例KClass

采用工厂模式来生产presenter

先创建一个工厂模式的接口:

interface IPresenterFactory<P> {/*** 创建presenter* */fun createPresenter():P
}

因为我的Presenter需要等到运行的时候才会知道是哪个,所以使用泛型P代表

创建具体的Presenter工厂类,在静态方法findClass中,通过传入的Activity获得Activity的注解,并通过注解获得相应的presenter的Class

在createPresenter方法中,通过presenter的Class反射生成presenter对象

class PresenterFactory<P>() :IPresenterFactory<P>{private var presenterKClass :KClass<*> ?=nullconstructor(presenterKClass :KClass<*>): this(){this.presenterKClass =presenterKClass}companion object{fun <P> findClass(viewClass:Class<*>) : PresenterFactory<P>{val annotation = viewClass.getAnnotation(Request::class.java)val value:KClass<*> =annotation.valuereturn PresenterFactory(value)}}override fun createPresenter(): P {return presenterKClass?.java!!.newInstance() as P}}

创建一个BasePresenter,实现IPresenter接口,将具体的View层的实例传过来。因为不知道具体的View是哪一个,所以使用泛型T表示

abstract class BasePresenter<T> :IPresenter{protected var mView: @UnsafeVariance T? = nullfun attachViewCompont(view: T) {mView = view}fun detechViewCompont() {mView = null}abstract fun setListeners()
}

为了实现设计模式的单一性原则,我们增加一个工厂类的代理类,来控制presenter的创建,已及view的绑定等操作:

class PresenterDelegate<P,V>() where P:BasePresenter<V>,V:IView {private var presenterFactory :IPresenterFactory<P>?=nullprivate var presenter :P ?=nullconstructor(presenterFactory :IPresenterFactory<P>):this(){this.presenterFactory =presenterFactory}open fun getPresenter():P{if(presenter!=null){return presenter!!}if (presenterFactory != null) {if (presenter == null) {presenter = presenterFactory?.createPresenter()}}return presenter!!}open fun setPresenter(presenter: P) {this.presenter = presenter}open fun bindViewCompont(view: IView) {if (presenter == null) {getPresenter()}if (presenter != null) {presenter!!.attachViewCompont(view as V)}}open fun unbindViewCompont() {if (presenter != null) {presenter!!.detechViewCompont()}}}

创建一个BaseActivity,继承AppCompatActivity实现IView接口,在BaseActivity中,通过创建工厂类的装饰类,创建具体的P层,并将P层和View层绑定

abstract class BaseActivity<P,V> :AppCompatActivity(),IView where P:BasePresenter<V>,V:IView{private var presenterDelegate = PresenterDelegate<P,V>(PresenterFactory.findClass(javaClass))protected val mViews = SparseArray<View>()protected var rootView: View? = nullprotected var mDecorView: View? = nullopen fun <T : View?> bindView(id: Int): T? {var view: T? = mViews[id] as Tif (view == null) {view = rootView?.findViewById(id)mViews.put(id, view)}return view}override fun getContext(): Context? {return this}override fun getRootViews(): View? {return rootView}override fun <T : View?> getView(id: Int): T {return bindView<View>(id) as T}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)presenterDelegate.bindViewCompont(this)rootView = layoutInflater.inflate(getLayoutId(), null, false)setContentView(rootView)initFields()bindEventListener()getPresenter().onCreate(savedInstanceState,this)getPresenter().setListeners()mDecorView = window.decorView}override fun onStart() {super.onStart()getPresenter().onStart()}override fun onRestart() {super.onRestart()getPresenter().onRestart()}override fun onResume() {super.onResume()getPresenter().onResume()}override fun onPause() {super.onPause()getPresenter().onPause()}override fun onStop() {super.onStop()getPresenter().onStop()}override fun onDestroy() {getPresenter().onDestroy()presenterDelegate.unbindViewCompont()super.onDestroy()}protected open fun onSaveInstanceState(outState: Bundle?) {super.onSaveInstanceState(outState!!)getPresenter().onSaveInstanceState(outState!!)}protected open fun onRestoreInstanceState(savedInstanceState: Bundle?) {super.onRestoreInstanceState(savedInstanceState!!)getPresenter().onRestoreInstanceState(savedInstanceState!!)}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)getPresenter().onActivityResult(requestCode, resultCode, data!!)}/*** 返回layout 布局文件的id** @return*/abstract fun getLayoutId(): Int/*** 初始化其他属性*/abstract fun initFields()/*** 设置监听*/abstract fun bindEventListener()open fun getPresenter(): P {return presenterDelegate.getPresenter()}open fun setPresenter(presenter: P) {presenterDelegate.setPresenter(presenter)}}

这样一个mvp架构就搭建完毕了,下面看看使用:

interface ITestView :IView {fun setContent(string: String)}

Module层:

class TestModule :IModule{fun doNetWork(){println("网络请求")}
}

Presenter层:

class TestPresenter: BasePresenter<ITestView>() {var module:TestModule? =nulloverride fun setListeners() {}override fun onCreate(savedInstanceState: Bundle?, mContext: Context?) {module =TestModule()}override fun onResume() {module?.doNetWork()mView?.setContent("222222222")}override fun onStart() {}override fun onRestart() {}override fun onPause() {}override fun onStop() {}override fun onDestroy() {}override fun onSaveInstanceState(outState: Bundle) {}override fun onRestoreInstanceState(savedInstanceState: Bundle) {}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {}}

View层:

@Request(TestPresenter::class)
class TestActivity :BaseActivity<TestPresenter,ITestView>(),ITestView {var textView:TextView?=nulloverride fun getLayoutId(): Int {return R.layout.activity_main}override fun initFields() {textView =findViewById<TextView>(R.id.txt)}override fun bindEventListener() {}override fun setContent(string: String) {textView?.text =string}override fun getActivity(): Activity? {return this}override fun getFragment(): Fragment? {return null}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/144254.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML - input type=file 允许用户选择多个文件

效果 示例 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><!-- When the multiple Boolean attribute is specified, the file input allows the user to select more than o…

No150.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

【项目】在线音乐播放器测试报告

目录 项目背景 项目功能 测试计划 功能测试 登录页面的测试 测试用例 测试结果 注册页面的测试 测试用例 测试结果 音乐列表页面的测试 测试用例 测试结果 出现的bug 搜索功能的bug 问题解决 删除功能的bug 问题解决 喜欢列表页面的测试 测试用例 测试结果…

电脑开机慢问题的简单处理

电脑用久了&#xff0c;开机时间要10-20分钟特别慢&#xff0c;一下介绍两种简单有效处理方式&#xff0c;这两种方式经测试不会影响原系统软件的使用&#xff1a; 方式一&#xff1a;禁用非必要启动项【效果不是很明显】 利用360里面的优化加速禁用启动项【禁用启动项还有其…

大数据分布式处理框架Hadoop

大数据是什么 大数据容量常以TB、PB、甚至EB为单位&#xff0c;远超传统数据库的承载能力&#xff0c;无论入库还是查询都出现性能瓶颈。 Hadoop是什么 Hadoop是开源的分布式计算技术框架&#xff0c;用于处理大规模数据和实现分布式存储。 Hadoop核心组件 HDFS&#xff08;…

【5G PHY】物理层逻辑和物理天线的映射

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

估计、偏差和方差

一、介绍 统计领域为我们提供了很多工具来实现机器学习目标&#xff0c;不仅可以解决训练集上的任务&#xff0c;还可以泛化。基本的概念&#xff0c;例如参数估计、偏差和方差&#xff0c;对于正式地刻画泛化、欠拟合和过拟合都非常有帮助。 二、参数估计 参数估计 是统计学…

公司新产品上线如何打出知名度?

任何一个新产品上线时都需要进行推广打出知名度&#xff0c;软文作为一种成本低效果留存时间长的营销方式能够让公司的新产品打出知名度&#xff0c;向潜在用户展示新产品的独特优势以及特性&#xff0c;下面就让媒介盒子告诉大家&#xff0c;新产品上线时&#xff0c;公司应该…

电脑技巧:笔记本电脑升级固态硬盘的注意事项,看完你就懂了

目录 1、接口类型 2、接口速率 3、固态硬盘的尺寸 4、发热情况 5、总结 如今的固态硬盘价格越来越便宜了&#xff0c;甚至某品牌4TB的PCIe4.0 M.2还爆出过不到900元的“报恩价”&#xff0c;让不少小伙伴都动了扩容甚至囤货的心思。但对于笔记本电脑用户来说&#xff0c;升…

小波变换学习笔记【1】

【声明】本博客为学习B站视频小波分解与重构所做笔记&#xff0c;供自己和大家查阅学习&#xff0c;想查看 up 原视频请移步 B 站&#xff0c;侵删。 1.1 小波变换的由来 傅里叶变换基本思想&#xff1a;将信号分解成一系列不同频率的连续正弦波的叠加。 其缺点是&#xff0c;…

华为鸿蒙4,3,2禁用Google谷歌服务框架,使用最新谷歌Google play服务

华为鸿蒙4,鸿蒙3,鸿蒙2有一些应用或者游戏尤其是游戏需要最新版的谷歌play服务支持才可以使用。但是华为的鸿蒙系统解决完”设备未经 play 保护机制认证”之后,最稳定的谷歌play服务是20这个版本&#xff0c;一旦升级到最新的Google谷歌play服务&#xff0c;目前是最新版本23这…

MySQL到TiDB:Hive Metastore横向扩展之路

作者&#xff1a;vivo 互联网大数据团队 - Wang Zhiwen 本文介绍了vivo在大数据元数据服务横向扩展道路上的探索历程&#xff0c;由实际面临的问题出发&#xff0c;对当前主流的横向扩展方案进行了调研及对比测试&#xff0c;通过多方面对比数据择优选择TiDB方案。其次分享了整…

c语言常用语法,长时间不用容易忘。

关键字 auto 声明自动变量const 定义常量&#xff0c;如果一个变量被 const 修饰&#xff0c;那么它的值就不能再被改变extern 声明变量或函数是在其它文件或本文件的其他位置定义register 声明寄存器变量signed 声明有符号类型变量或函数static 声明静态变量&#xff0c;修饰…

作用域 CSS 回来了

几年前&#xff0c;消失的作用域 CSS&#xff0c;如今它回来了&#xff0c;而且比以前的版本要好得多。 更好的是&#xff0c;W3C规范基本稳定&#xff0c;现在Chrome中已经有一个工作原型。我们只需要社区稍微关注一下&#xff0c;引诱其他浏览器构建它们的实现&#xff0c;并…

leetCode 198.打家劫舍 动态规划

198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#…

Hash Index 原理和应用精讲

线上沙龙 - 技术流第 35 期回放来啦 本期直播我们邀请到 KaiwuDB 高级研发工程师徐胜康&#xff0c;为大家分享 Hash Index 原理和应用。徐老师曾任职于 Sun Micro Systems, Lucent 等公司&#xff0c;具备多年 Linux/UNIX Operating System 内核、驱动、文件系统、数据库、研…

java生成PDF的Util

java使用itext生成pdf-CSDN博客 接上文 支持绘制表格 支持表格中的文本 字体加粗、字体上色、单元格背景上色&#xff0c; 支持拼接文本 支持单行文本 多种背景颜色、字体上色 支持自定义水印 废话不说先上效果图 工具类代码 package com.zxw.文件.PDF.util;import com.…

本地搭建kafka并用java实现发送消费消息

1、下载kafka的jar包文件 https://www.apache.org/dyn/closer.cgi?path/kafka/3.1.0/kafka_2.12-3.1.0.tgz2、下载完成直接操作命令启动 1、打开新的terminal(终端)窗口&#xff0c;进入kafka的bin目录 启动zk./zookeeper-server-start.sh ../config/zookeeper.properties2、…

LinkedList与链表

目录 一、Arraylist的缺陷 二、链表 2.1 链表的概念和结构 2.2 链表的实现 三、链表面试题 3.1 删除链表中所有值为val的节点 3.2 反转一个单链表 3.3 链表的中间节点 3.4 将有序链表合并 3.5 输出倒数第k个节点 3.6 链表分割 3.7 链表的回文结构 3.8 找两个链表的公共节…

现场直击|亚数TrustAsia精彩亮相IOTE深圳物联网展,CSA联盟展台等你来!

2023年9月20日&#xff0c;IOTE 2023第二十届深圳国际物联网展在深圳国际会展中心&#xff08;宝安&#xff09;顺利开幕。作为物联网领域年度最重要的行业盛会之一&#xff0c;本次展会汇聚全球来自工业、物流、基建、智慧城市、智慧零售等领域的600企业、10万行业人士&#x…