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.mzph.cn/news/90713.shtml

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

相关文章

FPGA的数字钟带校时闹钟报时功能VHDL

名称&#xff1a;基于FPGA的数字钟具有校时闹钟报时功能 软件&#xff1a;Quartus 语言&#xff1a;VHDL 要求&#xff1a; 1、计时功能:这是数字钟设计的基本功能&#xff0c;每秒钟更新一次,并且能在显示屏上显示当前的时间。 2、闹钟功能:如果当前的时间与闹钟设置的时…

【AI视野·今日NLP 自然语言处理论文速览 第四十四期】Fri, 29 Sep 2023

AI视野今日CS.NLP 自然语言处理论文速览 Fri, 29 Sep 2023 Totally 45 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers MindShift: Leveraging Large Language Models for Mental-States-Based Problematic Smartphone Use Interve…

软件测试(测试用例攻略)—写用例无压力

一、概念 测试用例的基本概念&#xff1a; 测试用例&#xff08;Test Case&#xff09;是为了实施测试而向被测试的系统提供的一组集合&#xff0c;这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素 。 主要步骤&#xff1a; 测试环境——测试步骤—…

C理解(二):指针,数组,字符串,函数

本文主要探讨指针&#xff0c;数组&#xff0c;字符串&#xff0c;函数 指针 int *p; 未绑定:*表示p为指针变量,占4字节 int a 1;p &a; 绑定:p与a地址绑定即p中存放a的地址 *p *p 1; 解引用:p间接访问a的存储空间…

【接口测试】HTTP协议

一、HTTP 协议基础 HTTP 简介 HTTP 是一个客户端终端&#xff08;用户&#xff09;和服务器端&#xff08;网站&#xff09;请求和应答的标准&#xff08;TCP&#xff09;。通常是由客户端发起一个请求&#xff0c;创建一个到服务器的 TCP 连接&#xff0c;当服务器监听到客户…

第十四届蓝桥杯大赛软件赛决赛 C/C++ 大学 B 组 试题 C: 班级活动

[蓝桥杯 2023 国 B] 班级活动 【问题描述】 小明的老师准备组织一次班级活动。班上一共有 n n n 名&#xff08; n n n 为偶数&#xff09;同学&#xff0c;老师想把所有的同学进行分组&#xff0c;每两名同学一组。为了公平&#xff0c;老师给每名同学随机分配了一个 n n …

以太坊智能合约的历史里程碑: 从DAO到数据隐私的技术演进

文章目录 系列文章目录前言一、时间线 项目介绍总结 前言 在短短的几年内&#xff0c;以太坊不仅成为了去中心化应用和智能合约的主导平台&#xff0c;而且也见证了区块链技术和应用的多次重大革命。本文详细回顾了自2016年至今&#xff0c;以太坊生态所经历的几个关键时刻与技…

leetcodetop100(29) K 个一组翻转链表

K 个一组翻转链表 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改…

React Native搭建Android开发环境

React Native搭建Android开发环境 搭建Android开发环境一、下载JDK二、安装Android Studio2.1 配置 ANDROID_HOME 环境变量 三、初始化项目 搭建Android开发环境 我的电脑是windows系统&#xff0c;所以只能搭建Android&#xff0c;如果电脑是mac&#xff0c;既可以搭建Androi…

修改sqlmap-Tamper脚本

修改sqlmap-Tamper脚本 文章目录 修改sqlmap-Tamper脚本1 sqlmap官网2 sql注入漏洞注入尝试3 环境&#xff1a;sqli-labs/Less-26a/3.1 尝试宽字节注入: 3.2 sqlmap使用3.3准备修改sqlmap使用 4 sqlmap中-tamper工厂&#xff08;输入输出&#xff09;4.1 [参考文章&#xff1a;…

蓝桥杯 题库 简单 每日十题 day11

01 质数 质数 题目描述 给定一个正整数N&#xff0c;请你输出N以内&#xff08;不包含N&#xff09;的质数以及质数的个数。 输入描述 输入一行&#xff0c;包含一个正整数N。1≤N≤10^3 输出描述 共两行。 第1行包含若干个素数&#xff0c;每两个素数之间用一个空格隔开&…

rust生命期

一、生命期是什么 生命期&#xff0c;又叫生存期&#xff0c;就是变量的有效期。 实例1 {let r;{let x 5;r &x;}println!("r: {}", r); }编译错误&#xff0c;原因是r所引用的值已经被释放。 上图中的绿色范围’a表示r的生命期&#xff0c;蓝色范围’b表示…

pygame实现跳跃发射子弹打怪效果

import pygame import sys,time,random from pygame.locals import * pygame.init() # 设置按下鼠标的时候一直触发 pygame.key.set_repeat(10, 10) # 加载背景图片 bg pygame.image.load(./img/bg.png) # 加载左方向行走和站立图片 heroLStand pygame.image.load(img/heroLs…

传统遗产与技术相遇,古彝文的数字化与保护

古彝文是中国彝族的传统文字&#xff0c;具有悠久的历史和文化价值。然而&#xff0c;由于古彝文的形状复杂且没有标准化的字符集&#xff0c;对其进行文字识别一直是一项具有挑战性的任务。本文介绍了古彝文合合信息的文字识别技术&#xff0c;旨在提高古彝文的自动识别准确性…

十七,IBL-打印各个Mipmap级别的hdr环境贴图

预滤波环境贴图类似于辐照度图&#xff0c;是预先计算的环境卷积贴图&#xff0c;但这次考虑了粗糙度。因为随着粗糙度的增加&#xff0c;参与环境贴图卷积的采样向量会更分散&#xff0c;导致反射更模糊&#xff0c;所以对于卷积的每个粗糙度级别&#xff0c;我们将按顺序把模…

【单片机】11-步进电机和直流电机

1.直流电机 1.什么是电机 电能转换为动能 2.常见电机 &#xff08;1&#xff09;交流电机【大功率】&#xff1a;两相【200W左右】&#xff0c;三相【1000W左右】 &#xff08;2&#xff09;直流电机【小功率】&#xff1a;永磁【真正的磁铁】&#xff0c;励磁【电磁铁】 &…

3种Renko图表形态FPmarkets3秒轻松判断价格走势

Renko图表形态在交易中的应用并不逊色于其他技术分析方法。相较于普通的烛台图表&#xff0c;使用Renko图表时&#xff0c;有些经典模式更容易被发现和识别&#xff0c;FPmarkets总结这些模式包括&#xff1a; 首先是头和肩膀形态。这是一种价格反转形态&#xff0c;由两个较小…

华为智能企业远程办公安全解决方案(1)

华为智能企业远程办公安全解决方案&#xff08;1&#xff09; 课程地址方案背景需求分析企业远程办公业务概述企业远程办公安全风险分析企业远程办公环境搭建需求分析 方案设计组网架构设备选型方案亮点 课程地址 本方案相关课程资源已在华为O3社区发布&#xff0c;可按照以下…

Java编码技巧:验证码

目录 1.1、EasyCaptcha&#xff08;优选&#xff0c;支持种类多&#xff0c;样式多&#xff0c;使用简单&#xff09;1.1.1、作用1.1.2、官方信息1.1.3、使用案例1.1.4、依赖1.1.5、代码1.1.6、效果1.1.7、拓展 1.2、kaptcha1.2.1、作用1.2.2、官方信息1.2.3、使用案例1.2.4、依…

SLAM从入门到精通(amcl定位使用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 学习slam&#xff0c;一般就是所谓的边定位、边制图的知识。然而在实际生产过程中&#xff0c;比如扫地机器人、agv、巡检机器人、农业机器人&…