{"id":13989107,"url":"https://github.com/UCodeUStory/S-MVP","last_synced_at":"2025-07-22T10:31:08.450Z","repository":{"id":190525111,"uuid":"106497275","full_name":"UCodeUStory/S-MVP","owner":"UCodeUStory","description":"🔥🔥优化版MVP,使用注解泛型简化代码编写，使用模块化协议方便维护，APT过程使用注解解析器利用JavaPoet🌝完成重复模块的编写，利用ASpect+GradlePlugin 完成横向AOP编程+Javassist动态字节码注入+Tinker实现热修复+Retrofit实现优雅网络操作+RxJava轻松玩转数据处理","archived":false,"fork":false,"pushed_at":"2019-08-23T08:21:00.000Z","size":38919,"stargazers_count":1086,"open_issues_count":2,"forks_count":126,"subscribers_count":48,"default_branch":"master","last_synced_at":"2025-05-24T06:09:30.292Z","etag":null,"topics":["android","apt","aspectj","gradle","hook","javassist","javassist-aop","lifecycle","mvp","retrofit2","rxjava"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/UCodeUStory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-10-11T02:47:47.000Z","updated_at":"2025-04-01T07:14:56.000Z","dependencies_parsed_at":"2023-08-25T03:40:41.475Z","dependency_job_id":null,"html_url":"https://github.com/UCodeUStory/S-MVP","commit_stats":null,"previous_names":["ucodeustory/s-mvp"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/UCodeUStory/S-MVP","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UCodeUStory%2FS-MVP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UCodeUStory%2FS-MVP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UCodeUStory%2FS-MVP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UCodeUStory%2FS-MVP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/UCodeUStory","download_url":"https://codeload.github.com/UCodeUStory/S-MVP/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UCodeUStory%2FS-MVP/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266475014,"owners_count":23934855,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","apt","aspectj","gradle","hook","javassist","javassist-aop","lifecycle","mvp","retrofit2","rxjava"],"created_at":"2024-08-09T13:01:31.553Z","updated_at":"2025-07-22T10:31:07.754Z","avatar_url":"https://github.com/UCodeUStory.png","language":"Java","readme":"\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"javascript:;\" rel=\"noopener\" target=\"_blank\"\u003e\u003cimg width=\"70%\" src=\"https://github.com/UCodeUStory/S-MVP/blob/master/sources/s_mvp_log.png\" alt=\"S-MVP logo\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/p\u003e\n\n\n\u003cdiv align=\"center\"\u003e\n\n![Language](https://img.shields.io/badge/language-Java-EE0000.svg)\n![](https://img.shields.io/badge/QQ-1483888222-green.svg)\n![SDK](https://img.shields.io/badge/SDK-14%2B-orange.svg) \n[![License](https://img.shields.io/apm/l/vim-mode.svg)](https://github.com/UCodeUStory/S-MVP/blob/master/LICENSE)\n\n\u003c/div\u003e\n\n### 引言\n\n-  **MVC时代**：在MVC模型里，更关注的Model的不变，业务需求通常是Model不变，同时有多个对Model的不同显示，即View。所以，在MVC模型里，Model不依赖于View，但是View是依赖于Model的。\n不仅如此，因为有一些业务逻辑在View里实现了，导致要更改View也是比较困难的，至少那些业务逻辑是无法重用的。\n\n-  **MVP时代**：在MVP里，Presenter完全把Model和View进行了分离，主要的程序逻辑在Presenter里实现。而且，Presenter与具体的View是没有直接关联的，而是通过定义好的接口进行交互（单独测试时我们只需要按照接口传递参数即可），从而使得在变更View时候可以保持Presenter的不变，即重用！ 不仅如此，我们还可以编写测试用的View，模拟用户的各种操作，从而实现对Presenter的测试--而不需要使用自动化的测试工具\n\n- **MVP解耦View时代**：以往我们的V层是一个Activity或Frament实现，大多数情况下，我们的一个页面布局很复杂,包含很多个ViewGroup,而不是简单的一个ListView、GridView，按照之前的会发现一个Activity中有很多Presenter来维护和很多的回调，有时我们只需要改动其中的一个ViewGroup内容逻辑，却不能很好的区分，所以我们要让每个View或者ViewGroup实现MVP，这样不管这个View放在哪(Activity/Fragment/ViewGroup)都能够很好的移植，并且修改某一个的时候也会互相不影响，所以通过LifeCycle和组件化View可以很好解决上面问题\n\n#### QQ群 806248089\n### 内容\n\n- #### 1.通过模块化减少了类的创建\n\n  常见写法：接口一个类，实现一个类，这样的MVP中就会出现6个类\n  \n  优化写法：Contract类管理接口,这样的MVP中只会出现4个类\n  \n- #### 2.通过注解，隐藏Presenter创建，减少代码\n\n  常见写法：需要在每个Activity中创建一个Presenter\n  \n  优化写法：在父类里拿到子类的名字进行创建，创建过程通过在要创建的Presenter添加上注解标识，在编译器动态生成代码\n\n- #### 3.添加Gradle插件使用Aspectj编译器\n\n- #### 4.通过Aspectj 实现TimeLog耗时打印，自定义Buidlconfig实现开关\n\n- #### 5.添加Lru缓存切片通过使用@MemoryCache注解\n\n- #### 6.添加登陆缓存切片用来检测是否登陆\n\n- #### 7.添加异常捕获，打印，保证程序不崩溃\n\n- #### 8.自定义BindView框架，通过@$(R.id.abc)作用在public类型的变量\n    1. 通过InjectView.bind();实现绑定\n    2. 通过InjectView.unbind();实现解绑\n    3. 支持在Activity和View中进行绑定\n\n- #### 9.通过javassist修改字节码的方式，可以生成类，也可以在某些特定方法注入代码，在保证不修改源码的情况，完成aop，避免代码碎片化\n\n- #### 10.通常我们一个页面需要不止一个请求，并且这些请求是异步的，这样可以得到很好的用户体验，往往我们还需要，等待这些请求都完成后做一些处理\n\n   这里封装一个Asynctask\n   \n   - 使用方法：\n      1. 创建一个SmartTaskManager,调用put方法传递一个要同步的线程数量，和指定一个key\n      2. 其他文件通过key获取Asynctask对象，在各线程执行完后调用Asynctask对象一个onFinish()方法\n      3. SmartTaskManager获取调用toEnd传递一个Runnable，当两个线程执行完后就会回调这个方法\n      4. 最后页面退出的时候移除这个task,SmartTaskManager.remove(key);\n   - 例子\n          \n           smartTaskManager = SmartTaskManager.as();\n           smartTaskManager.put(\"initTask\",2);\n           smartTaskManager.put(\"init\");\n           smartTaskManager.getAsyncTask(\"initTask\").toEnd(new Runnable() {\n               @Override\n               public void run() {\n                   Toast.makeText(getApplicationContext(),\"页面全部初始化完成\",Toast.LENGTH_SHORT).show();\n               }\n           });\n     \n- #### 11.业务中我们需要一个请求后调用另一个请求再调用其他请求，这种串行请求我们通常使用嵌套的形式，缺点很不好维护，如果要有需求要改变顺序，那需要改动很多的代码\n   \n   封装一个SyncTask\n   \n   - 使用方法：\n     1. 创建一个SmartTaskManager,调用put方法传递一个要同步的线程数量，和指定一个key\n     2. 其他文件通过key获取Synctask对象，在各线程执行完后调用Synctask对象一个onFinish(param)方法传递参数给下一个\n     3. 通过这个Synctask对象我们调用onNext，添加任务，添加的任务顺序，就是执行顺序\n     4. 调用start方法开始执行请求\n     5. 最后页面退出的时候移除这个task,SmartTaskManager.remove(key);\n   \n   - 例子：\n   \n         SyncTask stk = smartTaskManager.getSyncTask(\"init\");\n         stk.onNext(obj -\u003e initModel2.request_1())\n                 .onNext(obj -\u003e initModel2.request_2((String)obj))\n                 .onNext(obj -\u003e initModel2.request_3((String) obj, msg -\u003e Toast.makeText(getApplicationContext(),msg,Toast.LENGTH_SHORT).show()));\n\n         stk.start();\n   #### SmartTask结构\n   ![image](https://github.com/UCodeUStory/S-MVP/blob/master/smartManager.png)\n   \n- #### 12.添加LifeCycle实现组件化View开发\n    1. moudle下build.gradle 添加：\n   \n              compile \"android.arch.lifecycle:runtime:1.0.0-alpha4\"\n              compile \"android.arch.lifecycle:extensions:1.0.0-alpha4\"\n              annotationProcessor \"android.arch.lifecycle:compiler:1.0.0-alpha4\"\n              \n    2. 项目工程下build.gradle 添加：\n   \n           allprojects {\n               repositories {\n                   jcenter()\n                   google()\n                   mavenCentral()\n               }\n           }\n           \n- #### 13.以测试驱动开发应用程序,开发中先在AndroidTest编写好单元测试\n\n- #### 14.不建议使用DataBinding 因为会增加对布局的耦合，布局复用性就差了\n\n#### 架构图\n\n\u003cdiv align=\"center\"\u003e\n\u003cimg width=\"800\" height=\"425\" src=\"https://github.com/UCodeUStory/S-MVP/blob/master/framework.png\"/\u003e\n\u003c/div\u003e\n\n\n#### 我的相关技术仓库\n\n Repository | Repository | Repository | Repository\n---|---|---|---\n[组件化开发框架](https://github.com/UCodeUStory/ComponentDevelopment)  | [插件化开发框架](https://github.com/UCodeUStory/AndroidPluginFramework) | [Gradle插件开发](https://github.com/UCodeUStory/GradlePlugin)|[Tinker热修复例子](https://github.com/UCodeUStory/TinkerDemo)\n[事件状态机处理](https://github.com/UCodeUStory/StateMachine) | [MVVM设计](https://github.com/UCodeUStory/MVVM) | [JavaPoet](https://github.com/UCodeUStory/JavaPoetSample)| [Relax](https://github.com/UCodeUStory/Relax)\n\n#### Library\n\n1. [Retrofit](https://github.com/square/retrofit)\n2. [OKHttp](https://github.com/square/okhttp)\n3. [GSON](https://github.com/google/gson)\n4. [RxJava](https://github.com/ReactiveX/RxJava)\n5. [Glide](https://github.com/bumptech/glide)\n6. [LeakCanary](https://github.com/square/leakcanary)\n7. [Aspect](http://mvnrepository.com/artifact/org.aspectj/aspectjtools)\n\n\n****\n#### **框架待优化**\n\n\n3.使用Javassist注入字节码,这是一个很好的字节码编辑工具，提供在JVM运行期前修改的api\n\n4.路由实现简单的跳转，路由器也是用来解耦的，增加后台可配置性\n\n5.添加日志缓存框架,日志统一配置\n\n6.不是用RXjava情况下 处理取消网络请求，参数获取封装$(),封装Log\n\n7、性能监控：性能日志\n\n\n#### 处理流程\n 1. 在build 过程我们可以通过apt 生成java文件,再通过Aspectj解析，编织成class,最后我们还可以通过Javassist修改class和jar文件，最终打包成dex 到 apk\n\n\n \n#### 友情链接\n - [fly803/BaseProject](https://github.com/fly803/BaseProject) \n","funding_links":[],"categories":["Java"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FUCodeUStory%2FS-MVP","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FUCodeUStory%2FS-MVP","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FUCodeUStory%2FS-MVP/lists"}