XCoreRedux框架:Android UI组件化与Redux实践
XCoreRedux框架:Android UI组件化与Redux实践
@author: 莫川 https://github.com/nuptboyzhb/
XCoreRedux源码+Demo:https://github.com/nuptboyzhb/XCoreRedux
使用android studio打开该项目。
基于xcore框架写的一个小demo xcore
XCoreRedux核心代码库 pics
文档的pic资源 Android开发当中的Code Architecture思考
最近看了很多前端的框架,React、Flux、Redux等,React和Redux都是前端比较流行的框架。而android方面,Google官方貌似不太Care此事,业内也没有公认的优秀Architecture。与前端类似,在Android开发中,同样也面临着复杂的数据state管理的问题。在理解Store、Reducer和Action的基础上,最终,基于Redux+React的思想,提出了一个基于Android平台Redux框架,我给它起名叫作:XCoreRedux。本仓库就是XCoreRedux+UIComponent框架的实现。它表达的是一种思想,希望大家能够提出更好的意见。 XCoreRedux框架介绍
与前端的Redux框架类似,XCoreRedux框架的图示如下:
ActionAction 是把数据传到 store 的有效载体。它是store的唯一数据来源。我们一般是通过 store.dispatch()将action传到store中。Action一般需要两个参数:type类型和data数据。在XCoreRedux框架下,我们定义Action如下:
public class XCoreAction { //Action的类型 public final String type; //Action携带的value,可为空 public final Object value; public XCoreAction(String type, Object value) { this.type = type; this.value = value; public XCoreAction(String type) { this(type, null); @Override public boolean equals(Object object) { @Override public int hashCode() { }
为了统一的管理Action,你可以实现一个ActionCreator,比如,demo中创建了一个联系人业务的Creator:
* @version mochuan.zhb on 16/9/28. * @Author Zheng Haibo * @Blog github.com/nuptboyzhb * @Company Alibaba Group * @Description 联系人 ActionCreator public class ContactsActionCreator { public static final String ADD_ITEM = "AddContacts"; public static final String ADD_TITLE = "addCategory"; public static final String DELETE_LAST = "deleteLast"; public static final String CHECK_BOX = "contactsCheck"; public static XCoreAction addContacts(Contacts contacts) { return new XCoreAction(ADD_ITEM, contacts); public static XCoreAction addCategory(Title title) { return new XCoreAction(ADD_TITLE, title); public static XCoreAction deleteLast() { return new XCoreAction(DELETE_LAST); public static XCoreAction checkBoxClick(ContactsWrapper contactsWrapper) { return new XCoreAction(CHECK_BOX, contactsWrapper);
Action的概念比较好理解,下面我们看一下Reducer
Reducerreducer的字面意思就是“减速器”。Action描述了事件,Reducer是决定如何根据Action更新状态(state),而这正是reducer要做的事情。Reducer的接口定义如下:
public interface IXCoreReducer State { State reduce(State state, XCoreAction xcoreAction); }
就是根据输入的Action和当前的state,处理得到新的state。
(previousState, action) = newState
说的更直白一点,Reducer就是一些列 纯函数 的集合。如Demo中的项目所示:
public class ContactsReducer implements IXCoreReducer List XCoreRecyclerAdapter.IDataWrapper { * 添加联系人 * @param contactsWrappers * @param contacts * @return private List XCoreRecyclerAdapter.IDataWrapper addOneContacts(List XCoreRecyclerAdapter.IDataWrapper contactsWrappers, Contacts contacts) { return wrappers; * 添加标题 * @param contactsWrappers * @param value * @return private List XCoreRecyclerAdapter.IDataWrapper addOneTitle(List XCoreRecyclerAdapter.IDataWrapper contactsWrappers, Title value) { return wrappers; * 删除最后一个 * @param contactsWrappers * @return private List XCoreRecyclerAdapter.IDataWrapper deleteLast(List XCoreRecyclerAdapter.IDataWrapper contactsWrappers) { List XCoreRecyclerAdapter.IDataWrapper wrappers = new ArrayList (contactsWrappers); if (wrappers.size() 0) { wrappers.remove(wrappers.size() - 1); return wrappers; * 设置选择状态 * @param contactsWrappers * @param value * @return private List XCoreRecyclerAdapter.IDataWrapper changeCheckBoxStatus(List XCoreRecyclerAdapter.IDataWrapper contactsWrappers, ContactsWrapper value) { value.isChecked = !value.isChecked; return contactsWrappers; @Override public List XCoreRecyclerAdapter.IDataWrapper reduce(List XCoreRecyclerAdapter.IDataWrapper contactsWrappers, XCoreAction xcoreAction) { switch (xcoreAction.type) { case ContactsActionCreator.ADD_ITEM: return addOneContacts(contactsWrappers, (Contacts) xcoreAction.value); case ContactsActionCreator.ADD_TITLE: return addOneTitle(contactsWrappers, (Title) xcoreAction.value); case ContactsActionCreator.DELETE_LAST: return deleteLast(contactsWrappers); case ContactsActionCreator.CHECK_BOX: return changeCheckBoxStatus(contactsWrappers, (ContactsWrapper) xcoreAction.value); return contactsWrappers;
通过上面的Reducer实现,我们可以看出,Reducer就是一些列函数的集合,其中一个关键函数reduce,它按照action的不同type执行不同的方法处理。
Storestore字面意思是存储。在Redux框架下,Store和DataBase,File没有关系,它可不是持久化存储的意思。Store是负责管理数据源的状态,负责把Action和Reducer联系到一起。Store的职责为:
1.保存数据源的当前状态state 2.对外提供dispatch方法,更新state 3.通过subscribe注册监听器,当state变化时,通知观察者 4.提供getState方法,获取当前的stateStore的Java实现:
public class XCoreStore State { private final IXCoreReducer State mIXCoreReducer;//数据处理器-reducer private final List IStateChangeListener State listeners = new ArrayList ();//观察者 private volatile State state;//Store存储的数据 private XCoreStore(IXCoreReducer State mIXCoreReducer, State state) { this.mIXCoreReducer = mIXCoreReducer; this.state = state; * 内部dispatch * @param xCoreAction private void dispatchAction(final XCoreAction xCoreAction) throws Throwable { synchronized (this) { state = mIXCoreReducer.reduce(state, xCoreAction); for (IStateChangeListener State listener : listeners) { listener.onStateChanged(state);
public static S XCoreStore S create(IXCoreReducer S reducer, S initialState) { return new XCoreStore (reducer, initialState); public State getState() { return state;
public void subscribe(final IStateChangeListener State listener) { listeners.add(listener); * 注销 * @param listener public void unSubscribe(final IStateChangeListener State listener) { listeners.remove(listener); * 状态改变的回调接口 * @param S 状态 public interface IStateChangeListener S { void onStateChanged(S state);
在Android中,一个Redux页面(Fragment或者Activity) 只有一个单一的 store。当需要拆分数据处理逻辑时,应该使用 reducer组合,而不是创建多个Store。
搭配UIComponent与前端的Redux搭配React类似,XCoreRedux搭配UIComponent。
UI组件化(UIComponent)在前段的React框架下,我们常常听说组件的概念:‘UI组件’。那么什么是UI组件呢?以下图为例:
红色的区域为“普通组件”,绿色的区域为两种不同类型的“Item组件”。因此,在UIComponent里,组件分两种:普通组件和item组件(或称为cell组件)。
普通组件在XCore中是以FrameLayout的形式封装的,编写一个普通组件只需要实现如下方法:
3.实现XCoreStore中的IStateChangeListener接口,在onStateChanged中做数据绑定
为了使UI组件能够与Store进行关联,UI组件可以实现IStateChangeListener接口,然后作为观察者,观察Store的state变化。然后在onStateChanged方法中做数据绑定。
Item组件(Cell组件)
对于前端来说,item组件和普通组件并没有什么不同。但是对于Android或者iOS而言,item组件和普通组件是有本质区别的。以ReyclerView为例,Item组件在同一种类型下是会复用的。在XCoreRedux框架中,定义Item组件,需要继承自XCoreItemUIComponent,它本身并不是一个View。它只需要实现的方法有:
View onCreateView(LayoutInflater inflater,ViewGroup container);与Fragment的onCreateView类似,它负责创建item的布局View void onViewCreated(View view);
与Fragment的onViewCreated类似,在此写View的初始化 public String getViewType();
Item组件对于数据源的类型 public void bindView(IXCoreComponent coreComponent,
XCoreRecyclerAdapter coreRecyclerAdapter,
XCoreRecyclerAdapter.IDataWrapper data,
int pos);
数据绑定,当Adapter调用bindViewHolder时,会回调bindView方法。
Item组件需要通过Adapter,与对应的列表组件联系起来。针对Android常用的RecyclerView,XCoreRedux提供了插件式的通用XCoreRecyclerAdapter。
含列表组件下的XCoreRedux框架图与之前的不同之处在于,这里把整个列表封装成一个列表组件,对外提供注册Item,比如XCoreRecyclerViewComponent组件源码。
public class XCoreRecyclerViewComponent extends XCoreUIBaseComponent implements XCoreStore.IStateChangeListener List XCoreRecyclerAdapter.IDataWrapper { private SwipeRefreshLayout mSwipeRefreshLayout; private RecyclerView mRecyclerView; private RecyclerView.LayoutManager mLayoutManager; private XCoreRecyclerAdapter mXCoreRecyclerAdapter; public XCoreRecyclerViewComponent(Context context) { super(context); public XCoreRecyclerViewComponent(Context context, AttributeSet attrs) { super(context, attrs); public XCoreRecyclerViewComponent(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); @Override public final int getLayoutResId() { return R.layout.xcore_recyclerview_component; @Override public void onViewCreated(View view) { //初始化View mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.xcore_refresh_layout); mSwipeRefreshLayout.setEnabled(false); mRecyclerView = (RecyclerView) findViewById(R.id.xcore_rv); //初始化RecyclerView mLayoutManager = new LinearLayoutManager(getContext()); mRecyclerView.setLayoutManager(mLayoutManager); mXCoreRecyclerAdapter = new XCoreRecyclerAdapter(this); mRecyclerView.setAdapter(mXCoreRecyclerAdapter); public SwipeRefreshLayout getSwipeRefreshLayout() { return mSwipeRefreshLayout; public RecyclerView getRecyclerView() { return mRecyclerView; public RecyclerView.LayoutManager getLayoutManager() { return mLayoutManager; public XCoreRecyclerAdapter getXCoreRecyclerAdapter() { return mXCoreRecyclerAdapter; * 当状态发生变化时,自动通知 * @param status @Override public void onStateChanged(List XCoreRecyclerAdapter.IDataWrapper status) { mXCoreRecyclerAdapter.setDataSet(status); mXCoreRecyclerAdapter.notifyDataSetChanged(); * 对外提供item组件的注册 * @param xCoreItemUIComponent * @return public XCoreRecyclerViewComponent registerItemComponent(XCoreItemUIComponent xCoreItemUIComponent) { mXCoreRecyclerAdapter.registerItemUIComponent(xCoreItemUIComponent); return this; public void setRefreshEnable(boolean enable) { mSwipeRefreshLayout.setEnabled(enable); }
我们在使用该组件时,只需要:
1.在XML中添加组件
?xml version="1.0" encoding="utf-8"? LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" !-- 头部组件-- com.example.haibozheng.myapplication.components.container.HeaderComponent android:id="@+id/recycler_view_header_component" android:layout_width="match_parent" android:layout_height="wrap_content" / !-- 列表组件-- com.github.nuptboyzhb.xcore.components.impl.XCoreRecyclerViewComponent android:id="@+id/recycler_view_component" android:layout_width="match_parent" android:layout_height="match_parent" / /LinearLayout
2.初始化
//创建数据源的store mContactsListXCoreStore = XCoreStore.create(new ContactsReducer(), new ArrayList XCoreRecyclerAdapter.IDataWrapper //创建RecyclerView的UI组件 mXCoreRecyclerViewComponent = (XCoreRecyclerViewComponent) findViewById(R.id.recycler_view_component); //注册item组件模板 mXCoreRecyclerViewComponent.registerItemComponent(new TextItemComponent()) .registerItemComponent(new ImageItemComponent()); //创建头部组件 mHeaderComponent = (HeaderComponent) findViewById(R.id.recycler_view_header_component); //添加观察者 mContactsListXCoreStore.subscribe(mXCoreRecyclerViewComponent); mContactsListXCoreStore.subscribe(mHeaderComponent); ...组件之间通信
Item组件与列表组件及普通组件之间的通信。在本Demo中使用的EventBus是轻量级的otto。每一个继承自XCoreUIBaseComponent的组件,都已经在onCreate和onDestroy中分别进行了注册和反注册。使用时,只需要使用@Subscribe 注解来指定订阅方法。因此,在任意地方都可以调用:
XCoreBus.getInstance().post(action);
对于数据绑定方面,做了两个优化:
1.把数据通过Wrapper包装
2.使用UIBinderHelper做流式绑定,比如:
public class ImageItemComponent extends XCoreItemUIComponent implements View.OnClickListener { private UIBinderHelperImpl mUIBinderHelperImpl; @Override public void bindView(IXCoreComponent coreComponent, XCoreRecyclerAdapter coreRecyclerAdapter, XCoreRecyclerAdapter.IDataWrapper data, int pos) { mContactsWrapper = (ContactsWrapper) data; mUIBinderHelperImpl.from(R.id.item_content_tv).setText(mContactsWrapper.bindContentText()) .from(R.id.item_pic_iv).setImageUrl(mContactsWrapper.getAvatarUrl()) .from(R.id.item_title_tv).setText(mContactsWrapper.bindItemTitle()) .from(R.id.checkbox).setButtonDrawable(mContactsWrapper.isChecked ? R.mipmap.checkbox_checked : R.mipmap.checkbox_normal) .setOnClickListener(this); }2.Middleware中间件 3.与Rx结合 Redux中文文档 Flux and Android AndroidFlux一览
Fragment 是一种可以嵌入在 Activity 当中的 UI 片段,它能让程序更加合理和充分地利用大屏幕空间,因在平板上应用的非常广泛。
到这里你可能会有些懵,啥玩意?下面的举个例子:想象我们正在开发一个做一个页面,其中使用 RecyclerView 展示了一组新闻的标题,当点击了其中一个标题时,就打开另一个界面显示新闻的详细内容。如果...
相关文章
- [Android Pro] 终极组件化框架项目方案详解
- 【黑马Android】(04)数据库的创建和sql语句增删改查/LinearLayout展示列表数据/ListView的使用和BaseAdater/内容提供者创建
- Android 开发之旅:短信的收发及在android模拟器之间实践(二)
- 【Android 疑难杂症1】android.content.ActivityNotFoundException: Unable to find explicit activity class
- android虚拟机硬件加速问题
- 申请Google Map Android API Key
- 可能是目前市面上唯一能够支持全平台的RTMP推流组件:Windows、Linux、Android、iOS、ARM
- Android版OpenCV图像处理技术亲自验证[二十六]之2D过滤器(附源码)
- Android问题笔记 - Duplicate class
- Ubuntu下Android Studio连接手机无法识别
- 【Android 插件化】“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 )
- 【Android 进程保活】应用进程拉活 ( 系统 Service 机制拉活 | Service 组件 onStartCommand 方法分析 | 源码资源 )
- 2014 android毕设代做 代做Android毕设 安卓毕设
- android camera(一):camera模组CMM介绍
- Android的ViewAnimator而它的子类ViewSwitcher-android学习之旅(三十三)
- android app 的插件化、组件化、模块化开发
- Android 11.0 Folder文件夹全屏后文件夹图标列表居中时拖拽app到桌面的优化