android 部件库
Creating loosely-coupled Reactive Feature Components
创建松耦合的React性特征组件
总览 (Overview)
Re-usability is a pattern that solves the problem of duplication. It can be as simple as creating Functions, Classes, Interfaces to more complex UI-Components and Feature-Components.
可重用性是解决重复问题的一种模式。 它可以像创建功能,类,到更复杂的UI组件和功能组件的接口一样简单。
The article focuses initially on the re-usability of UI-Views(UIComponents) and then the FeatureComponents. Emphasis is on the Dependency-Inversion Principle, where both the Low-level(Feature Component) and High-level component (One incorporating the low-level components) both depend on abstraction, to create loosely-coupled systems.
本文首先关注UI-Views( UIComponents )的可重用性,然后是FeatureComponents的可重用性。 重点在于依赖关系反转原理 ,其中低级(功能组件)和高级组件(一个包含低级组件的组件)都依赖抽象,以创建松耦合的系统。
窥视UI组件[UI级] (A peek into UI Component [UI-level])
Before proceeding to Feature Components, we’ll start with a brief overview of UI-Components(re-usability of Views).
在继续进行功能组件之前,我们将首先简要概述UI组件(视图的可重用性)。
Data is sent downwards from HLC → LLC, while the Events are sent from the LLC → HLC.
数据从HLC→LLC向下发送,而事件从LLC→HLC发送。
Low-Level Component (UIComponent): It only renders itself based on the data provided by the High-level component. And propagates the events to the High-level component(👇). It’s devoid of business-logic.
低级组件(UIComponent):仅根据高级别组件提供的数据进行渲染。 并将事件传播到高级组件(👇)。 它没有业务逻辑。
class UIComponent(
private val data: ComponentData,
private val eventDispatch: UIComponentEventDispatch) {
// Renders based on the data provided by HLC
fun render(view: UIComponentView) {
view.data = data
view.invalidate()
}
fun onRandomEvent(payLoad: Data) {
// Sends the event to the HLC
eventDispatch.handleEvent1(payLoad)
}
}
interface UIComponentEventDispatch {
fun handleEvent1(payLoad: Data)
}
High-level Component: Provides the data for the UI-Components(LLC), and handles the events from the UIComponent(👇). Example: Click events. It holds all the business logic. It is a single source of truth that holds the state/data for all the UI-Component.
高级组件 :提供UI组件(LLC)的数据,并处理UIComponent(👇)中的事件。 示例:单击事件。 它包含所有业务逻辑。 它是保存所有UI组件的状态/数据的唯一事实来源。
class HighLevelComponent {
// Provides the data for UI component and passes the handler for handling events from UIComponent dispatch
val uiComponent = UIComponent(data, UIComponentEventHandler())
// Handles the events from the UIComponent.
inner class UIComponentEventHandler: UIComponentEventDispatch {
fun handleEvent1(payLoad: Data) { ... }
}
fun renderPage() {
uiComponent.render(uiComponentView)
}
}
React性特征组件 (Reactive Feature Component)
UIComponents are useful when there is re-usability of UI-views, while Feature Component has larger functionality.
当UI视图具有可重用性,而Feature Component具有更大的功能时,UIComponent很有用。
- Apart from receiving the data, it also produces the data itself. 除了接收数据之外,它还产生数据本身。
- Contains its own business-logic. 包含自己的业务逻辑。
- Needs lesser hand-holding than UIComponent and is useful for designing SDKs and standalone features. 与UIComponent相比,需要的握持较少,并且对设计SDK和独立功能很有用。
Why Reactive Feature Component?:- With multiple Components producing data, we need a way to synchronize them. Ex: Data produced by FC1 might affect FC2.
为什么使用React式特征组件?:-随着多个组件产生数据,我们需要一种同步它们的方法。 例如:FC1产生的数据可能会影响FC2。
We will take a bottom-up approach, where we Design and Implement the Low-level Feature components first, and later look their incorporation into the High-level Component.
我们将采用一种自下而上的方法,在该方法中,我们首先设计和实现低级功能组件,然后再将其合并到高级组件中。
低层特征组件(LLC)的设计。 (Design of Low-level Feature Components(LLC).)
For demonstration purposes, we build a Flight Booking screen. It includes the following four Low-level Feature Components DateSelection, FlightsSelection, HotelSelection, and SummaryComponent.
出于演示目的,我们构建了“航班预订”屏幕。 它包括以下四个低级功能组件DateSelection , FlightsSelection , HotelSelection和SummaryComponent。
The design of the FeatureComponent looks like this(👇)
FeatureComponent的设计如下所示(👇)
Let’s look at the Flight Feature Component
让我们看一下飞行功能组件
1. EventDispatcher (1. EventDispatcher)
Dispatches the events to High-level-Component. This is like a channel through which events are sent to the outside world(HLC).
将事件调度到高级组件。 这就像将事件发送到外界(HLC)的渠道。
interface EventDispatcher
/**
* Dispatches the events from the FlightFeatureComponent. This is like a channel through which we sent events to the outside world
* There are two types of event
* 1. Change in FeatureState needs to be propagated
* 2. Other events like Clicks that are controlled by the parent and not handled by the current FeatureComponent
*/
interface FlightEventDispatcher : EventDispatcher {
fun onFlightSelection(flight: Flight)
}
onFlightSelection
a flight selection event is sent to the outside world. This may then be used by another FeatureComponent.onFlightSelection
航班选择事件发送到外界。 然后,另一个FeatureComponent可以使用它。
2. EventReceiver (2. EventReceiver)
Feature Component receives the events from the High-level component.
功能组件从高级组件接收事件。
interface EventReceiver
interface FlightEventReceiver : EventReceiver {
// Change in date will let the FlightComponent to update itself.
// Makes an API call to fetch the flights for the specified date
fun dateChange(date: Date)
fun onRemoveSelection()
}
This is a gateway through which it receives events from the HLC.
这是一个网关,通过它从HLC接收事件。
dateChange
A change in date from another component is received. On reception, it fetches the flights for the said date.dateChange
收到另一个组件的日期更改。 在接收时,它将获取所述日期的航班。onRemoveSelection
clears the selected flight.onRemoveSelection
清除选定的航班。
3.用户界面 (3. UI)
The Feature Component has its own UI.
功能组件具有自己的UI。
interface UI<V : ViewGroup> {
fun render(view: V)
}
interface FeatureComponent<V:ViewGroup>: UI<V>
- Every FeatureComponent extends the UI interface, implying that they define their own UI. 每个FeatureComponent都扩展了UI界面,这意味着它们定义了自己的UI。
HLC attaches it.
render
is a public API for the HLC to render the FeatureComponent by passing the view(More detail later in Implementation 👇).HLC将其附加。
render
是HLC通过传递视图来渲染FeatureComponent的公共API(稍后在实现Implementation中进行详细介绍)。
底层组件的实现。 (Implementation of Low-level components.)
定义FeatureComponent合同 (Defining the FeatureComponent Contract)
interface FeatureComponent<V: ViewGroup, E: EventDispatcher> : UI<V> {
val eventDispatcher: E
}
- All FeatureComponents implement this interface. It is generic on EventDispatcher. 所有FeatureComponents都实现此接口。 它在EventDispatcher上是通用的。
1. EventDispatcher
1. EventDispatcher
class FlightFeatureComponent(
override val eventDispatcher: FlightEventDispatcher
) : FeatureComponent<FlightView, FlightEventDispatcher> {
fun onFlightSelected(flight: Flight) {
eventDispatcher.onFlightSelection(flight)
}
}
EventDispatcher
is a dependency of the Feature Component.EventDispatcher
是功能组件的依赖项。The component passes on the events to this interface. In this case, it sends the
selectedFlight
event.组件将事件传递到此接口。 在这种情况下,它将发送
selectedFlight
事件。
2. EventReceiver (2. EventReceiver)
class FlightFeatureComponent(
override val eventDispatcher: FlightEventDispatcher
) : FeatureComponent<FlightView, FlightEventDispatcher>, FlightEventReceiver {
private val store: FlightStore = TODO("Business logic implementation of Feature component")
override fun dateChange(date: Date) {
store.dispatchActions(FetchFlights(date))
}
override fun onRemoveSelection() {
store.dispatchActions(FlightAction.RemoveSelectedFlight)
}
}
Flight FeatureComponent implements the
FlightEventReceiver
interface. This provides it the capability to receive events from the HLC.Flight FeatureComponent实现了
FlightEventReceiver
接口。 这使它能够从HLC接收事件。In this case, it receives
dateChange
andremoveSelection
events and passes them to its business layer(store
).在这种情况下,它接收
dateChange
和removeSelection
事件,并将它们传递到其业务层(store
)。
3.定义和管理UI (3. Defining and managing the UI)
class FlightFeatureComponent(
override val eventDispatcher: FlightEventDispatcher
) : FeatureComponent<FlightView, FlightEventDispatcher>, FlightEventReceiver, FlightUiDelegate {
private val uiState = MutableStateFlow(FlightsUiState.initState())
private val store = FlightStore()
override fun render(view: FlightView) {
view.prepare(uiState, uiDelegate = this@FlightFeatureComponent)
}
override fun onFlightClick(flight: Flight) {
store.updateSelectedFlight(flight)
}
}
Flight FeatureComponent implements the
UI
interface on FlightView defining its own UI.Flight FeatureComponent在FlightView上实现了
UI
界面,定义了自己的UI。
Additionally, FeatureComponent additionally coordinates between its own business-layer and the view layer, by acting as a middle-man. (👇)
此外,FeatureComponent还通过充当中间人在其自己的业务层和视图层之间进行协调。 (👇)
高级组件的设计与实现(预订屏幕) (Design & Implementation of High-level Component(Booking screen))
Divide it into 2 parts — Business layer and View-Layer
将其分为两部分-业务层和视图层
1.业务层 (1. Business-layer)
class BookingScreenViewModel {
...
val flightComponent = FlightFeatureComponent(eventDispatcher = FlightEventDispatchListener())
// Listener to receive the events from the Component's EventReceiver
inner class FlightEventDispatchListener : FlightEventDispatcher {
override fun onFlightSelection(flight: Flight) {
// Handle the flight selection in the business layer of the Booking screen (HLC)
}
}
...
}
- It creates the Feature Components. 它创建功能部件。
To receive events from the FeatureComponents(LLC), HLC implements the dispatcher (
FlightEventDispatcher
) in the form of inner class (FlightEventDispatchListener
), which is then passed on as a dependency for component creation(👆).从 FeatureComponents(LLC),HLC 接收事件 以内部类(
FlightEventDispatchListener
)的形式实现调度程序(FlightEventDispatcher
),然后将其作为组件创建(👆)的依赖项传递。
class FlightFeatureComponent(): FlightEventReceiver
class BookingScreenViewModel {
...
val flightComponent = FlightFeatureComponent(eventDispatcher = FlightEventDispatchListener())
// An event to clear all the selections in the screen
fun clearSelections() {
flightComponent.onRemoveSelection()
}
...
}
To send events to Feature Component, HLC can directly call the methods of FlightComponent, as it has the capability to receive events. See
clearSelections
.要将事件发送到功能部件,HLC可以接收事件,因此可以直接调用FlightComponent的方法。 参见
clearSelections
。
2. 视图层 (2. View-layer)
class BookingScreen : Fragment() {
private val vm = MainViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
...
vm.flightComponent.render(flight_view)
}
}
- It is only responsible for rendering the FeatureComponents created by the business-layer. 它仅负责呈现业务层创建的FeatureComponents。
结论略有调整 (Conclusion with minor tweaks)
What if HLC components have a large number of components? The HLC would be over-burdened with synchronizing and passing the events between different FeatureComponents.
如果HLC组件包含大量组件怎么办? 通过在不同FeatureComponents之间同步和传递事件,HLC将负担沉重。
A better approach would be to make the HLC a mediator for passing events to FeatureComponents.
更好的方法是使HLC成为将事件传递给FeatureComponents的中介者。
- Whenever it receives an event from one FeatureComponent, it passes the event blindly to other FeatureComponents. 每当它从一个FeatureComponent接收到事件时,就会将该事件盲目传递给其他FeatureComponents。
- All FeatureComponent receive all the events but chooses the events on which they want to react and ignore the rest. 所有FeatureComponent都接收所有事件,但选择它们要对其作出React的事件,而忽略其余事件。
- This way both are loosely coupled and any component can be attached to the HLC. 这样,两者都可以松散耦合,并且任何组件都可以连接到HLC。
You can find the demonstration example here.
您可以在此处找到演示示例。
翻译自: https://proandroiddev.com/feature-components-in-android-6c193a65d73f
android 部件库