1 Star 1 Fork 0

山野羡民 / relight

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

开源地址: https://github.com/ittianyu/relight

优势

稳定

  • 减少内存泄漏:新手很容易在线程切换的地方写出导致内存泄漏的代码,但如果把线程切换交给框架来做,出错的概率就大大降低。
  • 减少 crash:根据我的开发经历,大部分 crash 都是空指针导致的。一般线程回调里最容易出现问题,当UI销毁后,子线程依旧去操作UI,容易导致 crash。 本框架有完善的生命周期,UI销毁后,框架对子线程做了强制的停止操作,大大减少 crash 的概率。

轻量

提示:这两个依赖库在 Android Studio 新建的项目里几乎都包含,也就是几乎 0 依赖。

接入成本低

  • 侵入性低:不需要修改任何现有代码
  • 无缝嵌入:可间接当做 View 使用,无论之前使用 MVP 还是 MVC,往里面加一个 View 根本不影响你的结构。

简单

  • 对原生开发友好:你几乎不需要学习框架 api 就可以开始使用。
  • 熟悉 react 和 flutter 的非常容易上手

具体可往下滑,查看基础教程。

解耦

MVVM 的强大之处在于 UI 和 逻辑 分离,处理逻辑时不需要关心 UI,写 UI 时不需要管数据从哪获取。

要更新时,你直接对数据进行修改,就会自动触发重新渲染。 并不需要担心性能问题,因为默认情况下,原来的 View 并不会被抛弃掉,仅仅会触发一次 update 操作。

public class StatefulUserWidget extends StatefulWidget<View, UserWidget> {
    private UserBean user = UserDataSource.getInstance().getUser();

    public StatefulUserWidget(Context context, Lifecycle lifecycle) {
        super(context, lifecycle);
    }

    @Override
    protected State<UserWidget> createState(Context context, Lifecycle lifecycle) {
        return StateUtils.create(new UserWidget(context, lifecycle, user));
    }

    @Override
    public void initWidget(UserWidget widget) {
        widget.setOnClickListener(v -> setState(() -> {
            user = UserDataSource.getInstance().getUser();
        }));
		update();
    }

    @Override
    public void update() {
        super.update();
        widget.setUser(user);
    }
}

initWidget 方法中对 widget 设置了一个点击事件,点击后重新获取数据,自动触发 UI 的更新。 其实就是调用了 setState 方法来触发更新,类似于 reactflutter,更新数据的操作需要放到该方法中,否则不会触发更新。

高复用

本框架的设计思想类似于 flutter 的 "Everything's a Widget",即把所有的东西都视为控件。 各个控件之间保持独立,容器控件可以组合一个或多个控件,每个控件都有独立的生命周期。 因此,控件的复用性大大提高。

便捷的生命周期

得益于谷歌新引进的 lifecycle,让每个 widget 都可以拥有完整的生命周期,甚至数据也可以拥有生命周期。

异步支持 (同步发请求)

对于客户端编程来说,最麻烦的是各种异步调用和状态同步。 多线程编程很难,稍有不慎,轻则内存泄漏,重则直接蹦溃。 本框架内部做了处理异步请求,并在 onDestroy 时,自动取消子线程的操作,防止内存泄漏 或者 异步导致的空指针问题。

本库提供了如下方法支持数据修改,各位开发者可自行选择合适的方法。

  • setState:同步执行数据修改操作(适用于非耗时的数据修改操作,无线程切换性能消耗)
  • setStateAsync:异步执行的数据修改操作,并在UI销毁时自动停止异步线程
  • setStateAsyncWithCache:类似于 setStateAsync ,对缓存提供支持。

有了它,你可以同步的方式去发网络请求。 合并多个请求的数据变得异常轻松(比如 先请求a,在请求b,合并结果变成c)。

缓存支持

生活 缓存很难。 一千个应用有一千种缓存。 我见过网上很多缓存方案非常粗糙,大部分是直接在网络层通过拦截器来做。 因为这样不用侵入到业务代码。 但是,这样做的弊端也很大,不够灵活。 虽然像 okhttp 这样的网络库提供了对缓存的支持,比如可以设置只使用缓存,或者只使用网络,但这依然不够灵活。

如果想精准控制缓存,那就不得不自己在代码里为每一个请求都加上缓存的逻辑。 你会发现这就导致相同的缓存逻辑写了无数遍,这简直是噩梦。

不过因为本库有异步支持,所以处理缓存也变得简单多了。 至于你想怎么使用缓存,交给你自己判断吧,我们提供了一个策略接口,你只需要实现它即可。

页面状态管理

无数据页面、 错误页面、 加载中页面、 下拉刷新、 加载更多 在应用中很常见。

实现起来却不方便了,常见的做法是 BaseActivity BaseFragment,但我表示不希望看见它们,曾今我觉得 base 是很好的逻辑抽象和封装,后来发现自从有了 base,迁移和复用几乎变成了 0。 base 使得它们紧紧的耦合在一起。 如果你不明白我在说什么,我给你举个例子:

我想从项目 A 中抽出一个页面和逻辑差不多的 Activity,以便于在项目 B 中使用,这个时候最常见的就是 复制 XxxActivity.java 到 B 项目,然后后面你懂的。

但本库对这几种页面状态提供了高度的封装,你不必再依赖于 Base。 不仅仅是 activity,甚至一个 button,你都可以让他拥有如上的这几种状态。

具体用法参考 进阶教程 1 3 4

请求过滤

不知道你是否烦恼过,产品跟你说,用户可能狂按按钮,让你加个判断,减少不必要的请求。 听起来需求很简单,防止重复点击就行,但可达鸭眉头一皱,发现事情并不简单。 一个按钮防重复点击也就几行代码,但几十个几百个按钮呢? 你说可以抽出一个 BaseButton? 那点击的如果是个 text 或 fab 这样的控件呢? 确实 base 可以解决很多重复代码,但相应的你要把对应的控件全部换成 base,工作量也很大。

本库贴心的为大家提供了请求过滤器,默认就过滤重复的请求,虽然不是在 UI 上过滤,但同一个 task 的请求是不会重复执行的,这点可以放心。 如果你有其他过滤需求,还可以自定义实现一个过滤器。

重试支持

请求失败重试也是很常见的需求,但实现并不简单,基本有2种做法:

  • 如果在代码层面做,就需要在请求失败的回调里重新发起一次,还要记录次数,很是麻烦。
  • 如果在网络层做,你就得对网络层进行一次封装,提供一个方法设置重试次数。 然而,这种方法弊端很大,不能和业务很好的联系。 因为网络层并不知道什么时候应该重试,网络请求失败就重试? 还是返回内容里面标识不成功就重试呢?

本库同样提供了重试支持,因为有了异步支持,重试对框架来说,就是一个循环,然而这个循环框架都帮你写好了,你只需告诉框架重试次数和什么时候应该重试就可以了。

动态属性设置能力

动态换肤或样式修改也是一个很常见的需求,然而为了实现这样的需求,往往需要开发者在代码里提前写好根据配置修改的UI的代码。

本库同样提供了支持,你可以通过一个 json 来对 wiget 进行属性修改。 所以换个皮肤或改个样式都是分分钟的事啦。

单页面应用(测试)

搞前端的应该很清楚这是什么,就是所有渲染都是在一个页面上展示,页面跳转都是通过前端路由来控制。 对应到客户端,就是所有 UI 都在一个 activity 中展示。

这样做有什么意义? 安卓插件化最大的问题是四大组件需要提前在 manifest 中注册,虽然目前有一些开源项目通过底层 hook 方式解决了这个问题,但是以后的安卓版本就不清楚会不会把这个限制了。 而且目前的插件化都需要对资源进行合并,这就使得成功率下降。

如果是单页面应用,动态下发字节码执行也变得有可能。 而且这样成功率理论上接近 100%。 打算有时间尝试一下。

我的意思就是像前端那样具有随时更新的能力,不知道会不会被封杀,逃。。。

快速开始

引入库

【可选】 添加 java8 支持

android {
...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
...
}

添加 maven 仓库

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

添加依赖

def support_version = '28.0.0'
def lifecycle_version = '1.1.1'

implementation 'com.github.ittianyu:relight:0.2.2'
implementation "com.android.support:appcompat-v7:$support_version"
implementation "com.android.support:design:$support_version"

// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"

如果开启了 java8

// alternately - if using Java8, use the following instead of compiler
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"

混淆

使用了 xml 支持,必须加入混淆,未使用的可以不加。

-keep class * extends com.ittianyu.relight.widget.Widget {*;}

入门教程

1. AndroidWidget

目的:学习 AndroidWidget 的简单用法。

2. StatefulWidget

目的:学习 StatefulWidget 的简单用法。

3. TextWidget

目的:学习 TextWidget 的简单用法,熟悉非 xml 的方式写界面。

4. LinearWidget

目的:学习 LinearWidget 的简单用法。

5. FrameWidget

目的:学习 FrameWidget 的简单用法

6. RelativeWidget

目的:学习 RelativeWidget 的简单用法

7. setStateAsync

目的:学习 setStateAsync 的使用。

进阶教程

1. LceeWidget

目的:学习 LceeWidget 的使用。

2. UpdateStrategy

目的:学习 AsyncState 的更新策略。

3.LceermWidget

目的:学习 LceermWidget 的使用。

4.RmWidget

目的:学习 RmWidget 的使用。

5.Retryable

目的:学习请求重试api。

6.Cache

目的:学习缓存机制。

7.StartActivity

目的:学习 Widget 中 startActivity 的用法。

8.xml

目的:了解 Widget xml 可视化支持

Widgets

前面说过本框架的设计思想是 "Everything's a Widget",Widget 是带有生命周期的原子性控件, 大致分为三类:native、stateful、stateless。

native

底层 widget。 直接涉及原生 view 的渲染。

  • AndroidWidget:所有 native 控件的基类,含有生命周期和 native 构建方法
  • BaseAndroidWidget:继承 AndroidWidget,封装了常用的 native 的属性和设置方法
  • ViewGroupWidget:继承 BaseAndroidWidget,类似于 ViewGroup,用于包容其他 AndroidWidget
  • FrameWidget:封装 FrameLayout
  • LinearWidget:封装 LinearLayout
  • RelativeWidget:封装 RelativeLayout
  • BaseTextWidget:封装了继承自 TextView 的所有 View 的常用属性和设置方法
  • TextWidget:封装 TextView
  • ImageWidget:封装 ImageView
  • ButtonWidget:封装 Button
  • EditWidget:封装 EditText
  • RecyclerWidget:封装 RecyclerView
  • SwipeRefreshWidget:封装 SwipeRefreshLayout

stateful

带有状态的控件。

  • StatefulWidget:所有 stateful 控件的基类,带有生命周期
  • LceeWidget:封装了 Loading、Content、Empty、Error 四种常见状态的控件
  • RmWidget:封装了 Refresh、LoadMore 两种常见状态的控件
  • LceermWidget:封装了 Loading、Content、Empty、Error、Refresh、LoadMore 六种常见状态的控件

stateless

无状态的控件。

  • StatelessWidget:所有 stateless 控件的基类,带有生命周期

异步线程策略

框架内部采用线程池来执行异步操作,考虑到不同的应用有不同的需求, 所以,开发者可以自行设置相应的线程池策略(建议在初始化时设置)。

ThreadPool.set(executorService);

默认使用的是 Executors.newCachedThreadPool(),也就是一段时间内没有异步任务时, 自动释放内部的线程,符合大部分应用的需求。

核心方法调用顺序

Widget

  • render: 外部通过调用 render 方法,获得一个 View,进行渲染
  • update: 当 StatefulWidget 状态变更时,被动触发

StatelessWidget

需要实现一个 Widget<T> build() 方法,来完成 Widget 的构建

render(first call) -> build -> widget.render -> initWidget

state

setState -> willUpdate -> update -> didUpdate

onDestroy -> dispose

StatefulWidget

需要实现一个 State<T> createState(Context context, Lifecycle lifecycle) 方法 来构建一个 State 对象

render(first call) -> createState -> state.init -> state.build -> widget.render -> initWidget

state.setState -> state.update -> widget.update

AndroidWidget

构造方法 -> createView

render(first call) -> initView -> initEvent -> initData

Lifecycle

带有生命周期的 Widget

  • 调用顺序
render(first call) -> bind lifecycle

需要注意的是,bind lifecycle 在控件初始化完之后才调用

  • 生命周期

通过绑定 Lifecycle 来让 Widget 获得完整的生命周期

onStart
onResume
onPause
onStop
onDestroy

BaseAndroidWidget

带有常用 View 属性设置的 native widget

initView -> initProps

onStart -> onViewAttachedToWindow -> updateProps(when has LayoutParams)

initView 是在 render 之后触发的

ViewGroupWidget

render(first call) -> children.render -> super.render(render self) -> add children to ViewGroup

addChildren -> updateChildrenProps -> updateProps

To Do List

框架

  • 基础框架
  • 异步支持
  • 重试支持
  • 过滤支持
  • 缓存支持
  • 完善 BaseAndroidWidget 基础属性 和 api
  • startActivity 支持
  • xml 支持
  • 单元测试支持
  • CoroutineState(kotlin 协程)
  • 应用状态管理(类似 redux mobx)
  • Android Studio 模版

基础控件

  • FrameWidget
  • LinearWidget
  • RelativeWidget
  • RecyclerWidget
  • TextWidget
  • ImageWidget
  • SwipeRefreshWidget
  • ButtonWidget
  • ToolbarWidget
  • EditWidget
  • FloatingActionButtonWidget
  • ScrollWidget
  • HorizontalScrollWidget
  • DrawerWidget

高级控件

  • LceeWidget
  • LceermWidget
  • RmWidget
  • ListWidget
  • HorizontalListWidget
  • Route、Navigator

主题控件

  • material
    • ChipWidget
    • ChipGroupWidget
    • MaterialButtonWidget
    • TextInputLayout
    • TextInputEditText

文档

  • 优势
  • 快速开始
  • 入门教程
  • 进阶教程
  • Widgets
  • 异步线程策略
  • 内部结构
  • 目录
  • 英文版
  • To Do List

致谢

感谢 贵州穿青人 一直以来的支持和帮忙

版权

Apache License 2.0

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

A light MVVM framework for Android. 一个轻量级的安卓MVVM框架 展开 收起
Android
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Android
1
https://gitee.com/li_yu_jiang/relight.git
git@gitee.com:li_yu_jiang/relight.git
li_yu_jiang
relight
relight
master

搜索帮助