Skip to content

Repository files navigation

Component Framework

LicensePlatformMin SDK

简体中文版说明 >>>

A lightweight, lifecycle-aware component framework for Android. One line of DSL sets up modular UI components with automatic lifecycle management, service communication, and dependency ordering.

Features

  • One-Line Setup -- componentScope { } DSL handles lifecycle binding, service registration, and dependency ordering automatically
  • Component Lifecycle -- Components mirror the host lifecycle with state guards to prevent invalid transitions
  • Service Communication -- Loosely-coupled inter-component messaging via type-safe getService<T>(), scoped per host
  • Dependency Ordering -- Declare dependencies; the framework topologically sorts components with circular dependency detection
  • Activity & Fragment -- Same component model works seamlessly in both Activity and Fragment contexts
  • Error Isolation -- Lifecycle propagation is wrapped in try-catch; one component failure does not crash others

Quick Start

1. Define a Component

classTitleBar(
host:ComponentHost,
privatevalbinding:LayoutTitleBarBinding,
) : Component(host), TitleBarService {
overridefunonCreate() {
binding.textTitle.text ="Hello"
}
overridefunsayHello(content:String) {
Log.d("TitleBar", "Received: $content")
}
}
interfaceTitleBarService : Service {
funsayHello(content:String)
}

2. Declare Dependencies & Access Services

classBottomBar(
host:ComponentHost,
privatevalbinding:LayoutBottomBarBinding,
) : Component(host), BottomBarService {
// Framework ensures TitleBar is created before BottomBaroverridefundependencies() =listOf(TitleBarService::class)
overridefunonCreate() {
val titleBar = getService<TitleBarService>()
titleBar?.sayHello("Hello from BottomBar")
}
}

3. Set Up in Activity

classMainActivity : AppCompatActivity() {
overridefunonCreate(savedInstanceState:Bundle?) {
super.onCreate(savedInstanceState)
val binding =ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
componentScope {
+TitleBar(host, binding.titleBarContent)
+ContentLayout(host, binding.layoutContent)
+BottomBar(host, binding.bottomBarContent)
}
}
}

4. Set Up in Fragment

classDemoFragment : Fragment(R.layout.fragment_demo) {
overridefunonViewCreated(view:View, savedInstanceState:Bundle?) {
val binding =FragmentDemoBinding.bind(view)
componentScope {
+HeaderComponent(host, binding.header)
+ContentComponent(host, binding.content)
}
}
}

That's it. Lifecycle binding, service registration, dependency sorting, and cleanup are all automatic.

Architecture

Overall Structure

graph TB
subgraph Host["Activity / Fragment"]
DSL["componentScope { }"]
end
DSL --> Scope["ComponentScope<br/><i>DSL receiver + service registry</i>"]
DSL --> Container["ComponentContainer<br/><i>lifecycle propagation + topo sort</i>"]
DSL --> HostAdapter["ComponentHost<br/><i>Activity/Fragment adapter</i>"]
Scope --> |registers| Services["Service Registry<br/><i>per-scope, no global state</i>"]
Container --> |manages| Components
subgraph Components["Components"]
C1["TitleBar<br/>implements TitleBarService"]
C2["ContentLayout"]
C3["BottomBar<br/>implements BottomBarService"]
C4["NoneUiComponent"]
end
C3 -.->|"getService&lt;TitleBarService&gt;()"| Services
C2 -.->|"getService&lt;BottomBarService&gt;()"| Services
HostAdapter --> |lifecycle events| Container
Loading

Lifecycle Flow

sequenceDiagram
participant A as Activity/Fragment
participant S as ComponentScope
participant C as ComponentContainer
participant Comp as Components
A->>S: componentScope { }
S->>S: +Component(host, binding)
S->>S: register Service interfaces
S->>C: pass components list
C->>C: topological sort by dependencies()
A->>C: ON_CREATE
C->>Comp: performCreate() (in dependency order)
A->>C: ON_START / ON_RESUME
C->>Comp: performStart() / performResume()
A->>C: ON_PAUSE / ON_STOP
C->>Comp: performPause() / performStop()
A->>C: ON_DESTROY
C->>Comp: performDestroy()
C->>S: release services
Loading

Component State Machine

stateDiagram-v2
[*] --> INITIALIZED
INITIALIZED --> CREATED: performCreate()
CREATED --> STARTED: performStart()
STARTED --> RESUMED: performResume()
RESUMED --> PAUSED: performPause()
PAUSED --> RESUMED: performResume()
PAUSED --> STOPPED: performStop()
STOPPED --> STARTED: performStart()
STOPPED --> DESTROYED: performDestroy()
CREATED --> DESTROYED: performDestroy()
DESTROYED --> [*]
Loading

Core Classes

ClassRole
ComponentBase class with lifecycle callbacks, state machine, and dependency declaration
ServiceMarker interface for inter-component communication
ComponentHostHost environment abstraction (lifecycle, context, ViewModel store)
componentScope()DSL entry point -- creates host, scope, container, binds lifecycle
getService<T>()Type-safe service lookup extension on Component

Internal Classes (users don't need to know)

ClassRole
ComponentContainerManages components, propagates lifecycle, topological sort
ComponentScopeDSL receiver, scope-local service registry
ActivityComponentHostComponentHost adapter for Activity (Kotlin by delegation)
FragmentComponentHostComponentHost adapter for Fragment (view lifecycle)

Project Structure

component-framework/
├── src/main/java/com/andy/modularization/ # Core framework library
│ ├── Component.kt # Base component + state machine
│ ├── ComponentHost.kt # Host abstraction interface
│ ├── ComponentContainer.kt # Lifecycle container + dependency sort
│ ├── ComponentScope.kt # DSL receiver + scope-local service registry
│ ├── ComponentKt.kt # componentScope() DSL + extensions
│ ├── Service.kt # Service marker interface
│ ├── ActivityComponentHost.kt # Activity adapter (by-delegation)
│ └── FragmentComponentHost.kt # Fragment adapter (view lifecycle)
│
├── app/ # Demo application
│ └── src/main/java/com/andy/modules/
│ ├── ui/ # Activity-scoped components
│ └── fragment/ # Fragment demo

Integration

Step 1: Add JitPack repository

// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}

Step 2: Add dependency

dependencies {
implementation("com.github.andyhaha:component-framework:v2.0.0")
}

Demo Preview

Demo Preview

Requirements

  • Android SDK 23+
  • Kotlin 2.0+
  • AndroidX AppCompat

License

Copyright 2024 Andy
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.

About

Using a 'componentization' development approach to handle complex pages or business logic.

Resources

Stars

31 stars

Watchers

5 watching

Forks

Releases

Packages

Contributors

Languages