Skip to content

andyhaha/component-framework

Repository files navigation

Component Framework

License Platform Min 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

class TitleBar(
    host: ComponentHost,
    private val binding: LayoutTitleBarBinding,
) : Component(host), TitleBarService {

    override fun onCreate() {
        binding.textTitle.text = "Hello"
    }

    override fun sayHello(content: String) {
        Log.d("TitleBar", "Received: $content")
    }
}

interface TitleBarService : Service {
    fun sayHello(content: String)
}

2. Declare Dependencies & Access Services

class BottomBar(
    host: ComponentHost,
    private val binding: LayoutBottomBarBinding,
) : Component(host), BottomBarService {

    // Framework ensures TitleBar is created before BottomBar
    override fun dependencies() = listOf(TitleBarService::class)

    override fun onCreate() {
        val titleBar = getService<TitleBarService>()
        titleBar?.sayHello("Hello from BottomBar")
    }
}

3. Set Up in Activity

class MainActivity : AppCompatActivity() {
    override fun onCreate(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

class DemoFragment : Fragment(R.layout.fragment_demo) {
    override fun onViewCreated(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

Class Role
Component Base class with lifecycle callbacks, state machine, and dependency declaration
Service Marker interface for inter-component communication
ComponentHost Host 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)

Class Role
ComponentContainer Manages components, propagates lifecycle, topological sort
ComponentScope DSL receiver, scope-local service registry
ActivityComponentHost ComponentHost adapter for Activity (Kotlin by delegation)
FragmentComponentHost ComponentHost 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

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages