├── .gitattributes ├── .gitignore ├── .idea └── .gitignore ├── README.md ├── README_cn.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── andy │ │ └── modules │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── andy │ │ │ └── modules │ │ │ ├── MainActivity.kt │ │ │ ├── MainActivityDelegate.kt │ │ │ ├── MainComponentFactory.kt │ │ │ ├── component │ │ │ └── NoneUiComponent.kt │ │ │ └── ui │ │ │ ├── BottomBar.kt │ │ │ ├── ContentLayout.kt │ │ │ └── TitleBar.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── layout_bottom_bar.xml │ │ ├── layout_content_main.xml │ │ └── layout_title_bar.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── navigation │ │ └── nav_graph.xml │ │ ├── values-land │ │ └── dimens.xml │ │ ├── values-night │ │ └── themes.xml │ │ ├── values-v23 │ │ └── themes.xml │ │ ├── values-w1240dp │ │ └── dimens.xml │ │ ├── values-w600dp │ │ └── dimens.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── com │ └── andy │ └── modules │ └── ExampleUnitTest.kt ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libs └── modularization │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── andy │ │ └── modularization │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── andy │ │ └── modularization │ │ ├── ActivityContainer.kt │ │ ├── ActivityLifeCycle.kt │ │ ├── Component.kt │ │ ├── Container.kt │ │ ├── HolderIdProvider.kt │ │ ├── Service.kt │ │ ├── ServiceManager.kt │ │ └── StateHandle.kt │ └── test │ └── java │ └── com │ └── andy │ └── modularization │ └── ExampleUnitTest.kt └── settings.gradle.kts /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | /.idea 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | local.properties 17 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Modularization Architecture Example 2 | 3 | ![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen) 4 | 5 | [简体中文版说明 >>>](https://github.com/andyhaha/modules/blob/main/README_cn.md) 6 | 7 | ## Project Overview 8 | 9 | This project demonstrates a modularization architecture based on Kotlin and Android. By using modularization, we can split an app into multiple independent modules, each of which can either be UI-related or non-UI-related, depending on the requirements. Components communicate via Services, achieving decoupling and increasing code reusability. 10 | 11 | This architecture supports dynamic loading and unloading of components across different Activities, while also allowing communication between components via Services for flexible management and extension. 12 | 13 | ## Features 14 | 15 | - **UI Modularization**: Each component can be related to UI, such as `TitleBar`, `Content`, and `BottomBar`, or non-UI functionality. 16 | - **Service Communication**: Components communicate via Services, achieving decoupling. 17 | - **Dynamic Loading & Management**: Components can be dynamically loaded, initialized, and destroyed, with management via a unified factory. 18 | - **Activity Lifecycle Management**: Components manage their lifecycle based on the Activity lifecycle to avoid memory leaks and resource wastage. 19 | ## Architecture Design 20 | 21 | ### Core of Modularization Architecture 22 | 23 | - **Component Class**: Each component extends the `Component` class, which manages the lifecycle and binds the Activity and View. 24 | - **Factory Class**: The `ComponentFactory` class is used to create and manage all component instances, providing a unified interface for retrieving, registering, and destroying components. 25 | - **Service Manager**: The `ServiceManager` class provides a mechanism for communication between components using Services. 26 | - **MainActivityDelegate**: The `MainActivityDelegate` class manages the creation, lifecycle, and destruction of components via delegation. 27 | 28 | ## How to Use 29 | 30 | 1. **Add Modules**: To add a new module, create a new class extending `Component` in the `modules/` directory. 31 | 2. **Register Components**: Use the `ComponentFactory` to register and manage your components. 32 | 3. **Service Communication**: To enable communication between components, use `ServiceManager` to send and receive messages. 33 | 4. **Activity Integration**: Ensure that your components are integrated into the activity lifecycle through `MainActivityDelegate`. 34 | 35 | ## License 36 | 37 | Copyright (c) [2024] [Andy] 38 | 39 | Permission is hereby granted, free of charge, to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of this software, and to permit others to do so, subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 44 | -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 | # 模块化架构示例 2 | 3 | ## 项目概述 4 | 5 | 本项目展示了基于 Kotlin 和 Android 的模块化架构。通过使用模块化,我们可以将一个应用拆分成多个独立的模块,每个模块可以是与 UI 相关的或与非 UI 功能相关的,具体取决于需求。组件通过服务进行通信,实现解耦和提高代码复用性。 6 | 7 | 该架构支持不同 Activity 中组件的动态加载和卸载,同时允许组件之间通过服务进行通信,灵活管理和扩展。 8 | 9 | ## 特性 10 | 11 | - **模块化**:每个组件可以是与 UI 相关的,例如 `TitleBar`、`Content` 和 `BottomBar`,也可以是非 UI 功能。 12 | - **服务通信**:组件之间通过服务进行通信,实现解耦。 13 | - **动态加载与管理**:组件可以动态加载、初始化和销毁,并通过统一的工厂进行管理。 14 | - **Activity 生命周期管理**:组件根据 Activity 生命周期来管理自身的生命周期,避免内存泄漏和资源浪费。 15 | 16 | ## 架构设计 17 | 18 | ### 模块化架构的核心 19 | 20 | - **组件类**:每个组件继承自 `Component` 类,该类管理组件的生命周期,并绑定 Activity 和 View。 21 | - **工厂类**:`ComponentFactory` 类用于创建和管理所有组件实例,提供统一的接口用于获取、注册和销毁组件。 22 | - **服务管理器**:`ServiceManager` 类提供组件之间通过服务进行通信的机制。 23 | - **MainActivityDelegate**:`MainActivityDelegate` 类通过委托方式管理组件的创建、生命周期和销毁。 24 | 25 | ## 使用方式 26 | 27 | 1. **添加模块**:要添加一个新模块,请在 `modules/` 目录中创建一个继承自 `Component` 的新类。 28 | 2. **注册组件**:使用 `ComponentFactory` 来注册和管理您的组件。 29 | 3. **服务通信**:要启用组件之间的通信,使用 `ServiceManager` 发送和接收消息。 30 | 4. **集成 Activity**:确保您的组件通过 `MainActivityDelegate` 集成到 Activity 生命周期中。 31 | 32 | ## 许可证 33 | 34 | 版权所有 (c) [2024] [Andy] 35 | 36 | 特此免费授予使用、复制、修改、合并、发布、分发、再许可和/或出售本软件的副本,以及允许他人这样做的权限,但须遵守以下条件: 37 | 38 | 上述版权声明和本许可声明应包含在本软件的所有副本或重要部分中。 39 | 40 | 本软件按“原样”提供,不附任何明示或暗示的担保,包括但不限于适销性、特定用途的适用性和非侵权的担保。在任何情况下,作者或版权持有者均不对因使用本软件或与本软件有关的行为所引起的任何索赔、损害或其他责任负责。 41 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.application) 3 | alias(libs.plugins.kotlin.android) 4 | } 5 | 6 | android { 7 | namespace = "com.andy.modules" 8 | compileSdk = 35 9 | 10 | defaultConfig { 11 | applicationId = "com.andy.modules" 12 | minSdk = 23 13 | targetSdk = 35 14 | versionCode = 1 15 | versionName = "1.0" 16 | 17 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | isMinifyEnabled = false 23 | proguardFiles( 24 | getDefaultProguardFile("proguard-android-optimize.txt"), 25 | "proguard-rules.pro" 26 | ) 27 | } 28 | } 29 | compileOptions { 30 | sourceCompatibility = JavaVersion.VERSION_11 31 | targetCompatibility = JavaVersion.VERSION_11 32 | } 33 | kotlinOptions { 34 | jvmTarget = "11" 35 | } 36 | buildFeatures { 37 | viewBinding = true 38 | } 39 | } 40 | 41 | dependencies { 42 | 43 | implementation(libs.androidx.core.ktx) 44 | implementation(libs.androidx.appcompat) 45 | implementation(libs.material) 46 | implementation(libs.androidx.constraintlayout) 47 | implementation(libs.androidx.navigation.fragment.ktx) 48 | implementation(libs.androidx.navigation.ui.ktx) 49 | testImplementation(libs.junit) 50 | androidTestImplementation(libs.androidx.junit) 51 | androidTestImplementation(libs.androidx.espresso.core) 52 | 53 | implementation(project(":libs:modularization")) 54 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/andy/modules/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.andy.modules 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.andy.modules", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/andy/modules/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.andy.modules 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.andy.modules.databinding.ActivityMainBinding 6 | 7 | class MainActivity : AppCompatActivity() { 8 | 9 | private lateinit var binding: ActivityMainBinding 10 | private var mainActivityDelegate: MainActivityDelegate? = null 11 | 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | binding = ActivityMainBinding.inflate(layoutInflater) 15 | setContentView(binding.root) 16 | mainActivityDelegate = MainActivityDelegate( 17 | activity = this, 18 | binding = binding 19 | ) 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/andy/modules/MainActivityDelegate.kt: -------------------------------------------------------------------------------- 1 | package com.andy.modules 2 | 3 | import androidx.lifecycle.Lifecycle 4 | import androidx.lifecycle.LifecycleEventObserver 5 | import androidx.lifecycle.LifecycleOwner 6 | import com.andy.modularization.ActivityContainer 7 | import com.andy.modularization.ActivityLifeCycle 8 | import com.andy.modules.databinding.ActivityMainBinding 9 | import java.lang.ref.WeakReference 10 | 11 | class MainActivityDelegate( 12 | private val activity: MainActivity, 13 | private val binding: ActivityMainBinding, 14 | ) : ActivityLifeCycle { 15 | init { 16 | activity.lifecycle.addObserver(InnerLifecycleObserver(this)) 17 | } 18 | 19 | private val roomContainer by lazy(LazyThreadSafetyMode.NONE) { 20 | ActivityContainer(activity) 21 | } 22 | 23 | private val componentFactory by lazy(LazyThreadSafetyMode.NONE) { 24 | MainComponentFactory(activity, binding) 25 | } 26 | 27 | override fun onCreate() { 28 | roomContainer.onCreate() 29 | componentFactory.newComponents() 30 | componentFactory.components().forEach { 31 | roomContainer.addComponent(it) 32 | } 33 | } 34 | 35 | override fun onStart() { 36 | roomContainer.onStart() 37 | } 38 | 39 | override fun onResume() { 40 | roomContainer.onResume() 41 | } 42 | 43 | override fun onPause() { 44 | roomContainer.onPause() 45 | } 46 | 47 | override fun onStop() { 48 | roomContainer.onStop() 49 | } 50 | 51 | override fun onDestroy() { 52 | roomContainer.onDestroy() 53 | componentFactory.release() 54 | } 55 | 56 | class InnerLifecycleObserver(delegate: MainActivityDelegate) : LifecycleEventObserver { 57 | private val activityDelegate = WeakReference(delegate) 58 | 59 | override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { 60 | when (event) { 61 | Lifecycle.Event.ON_CREATE -> { 62 | activityDelegate.get()?.onCreate() 63 | } 64 | Lifecycle.Event.ON_START -> { 65 | activityDelegate.get()?.onStart() 66 | } 67 | Lifecycle.Event.ON_RESUME -> { 68 | activityDelegate.get()?.onResume() 69 | } 70 | Lifecycle.Event.ON_PAUSE -> { 71 | activityDelegate.get()?.onPause() 72 | } 73 | Lifecycle.Event.ON_STOP -> { 74 | activityDelegate.get()?.onStop() 75 | } 76 | Lifecycle.Event.ON_DESTROY -> { 77 | activityDelegate.get()?.onDestroy() 78 | } 79 | else -> { 80 | // Handle other lifecycle events here if needed 81 | } 82 | } 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /app/src/main/java/com/andy/modules/MainComponentFactory.kt: -------------------------------------------------------------------------------- 1 | package com.andy.modules 2 | 3 | import androidx.appcompat.app.AppCompatActivity 4 | import com.andy.modularization.Component 5 | import com.andy.modularization.Service 6 | import com.andy.modularization.ServiceManager 7 | import com.andy.modularization.holderId 8 | import com.andy.modules.component.NoneUiComponent 9 | import com.andy.modules.databinding.ActivityMainBinding 10 | import com.andy.modules.ui.BottomBar 11 | import com.andy.modules.ui.ContentLayout 12 | import com.andy.modules.ui.TitleBar 13 | 14 | class MainComponentFactory( 15 | private val activity: AppCompatActivity, 16 | private val binding: ActivityMainBinding, 17 | ) : Component.ComponentFactory { 18 | private val components = mutableListOf() 19 | 20 | override fun newComponents() { 21 | addComponent(TitleBar(activity, binding.titleBarContent)) 22 | addComponent(ContentLayout(activity, binding.layoutContent)) 23 | addComponent(BottomBar(activity, binding.bottomBarContent)) 24 | addComponent(NoneUiComponent(activity)) 25 | } 26 | 27 | private fun addComponent(component: Component) { 28 | components.add(component) 29 | if (component is Service) { 30 | ServiceManager.registerService(component.holderId, component) 31 | } 32 | } 33 | 34 | override fun components(): List { 35 | return components 36 | } 37 | 38 | override fun release() { 39 | components.forEach { 40 | ServiceManager.releaseHolderServices(it.holderId) 41 | } 42 | components.clear() 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/andy/modules/component/NoneUiComponent.kt: -------------------------------------------------------------------------------- 1 | package com.andy.modules.component 2 | 3 | import android.util.Log 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.andy.modularization.Component 6 | 7 | /** 8 | * A component that is unrelated to the UI. 9 | * It handles non-visual logic or background tasks. 10 | */ 11 | class NoneUiComponent( 12 | override val activity: AppCompatActivity 13 | ) : Component() { 14 | 15 | companion object { 16 | private const val TAG = "NoneUiComponent" 17 | } 18 | 19 | override fun onCreate() { 20 | Log.d(TAG, "onCreate: Initializing NoneUiComponent") 21 | } 22 | 23 | override fun onStart() { 24 | Log.d(TAG, "onStart: NoneUiComponent started") 25 | } 26 | 27 | override fun onResume() { 28 | Log.d(TAG, "onResume: NoneUiComponent resumed") 29 | } 30 | 31 | override fun onPause() { 32 | Log.d(TAG, "onPause: NoneUiComponent paused") 33 | } 34 | 35 | override fun onStop() { 36 | Log.d(TAG, "onStop: NoneUiComponent stopped") 37 | } 38 | 39 | override fun onDestroy() { 40 | Log.d(TAG, "onDestroy: NoneUiComponent destroyed") 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/andy/modules/ui/BottomBar.kt: -------------------------------------------------------------------------------- 1 | package com.andy.modules.ui 2 | 3 | import android.util.Log 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.andy.modularization.Component 6 | import com.andy.modularization.Service 7 | import com.andy.modularization.getString 8 | import com.andy.modules.R 9 | import com.andy.modules.databinding.LayoutBottomBarBinding 10 | 11 | class BottomBar( 12 | override val activity: AppCompatActivity, 13 | private val binding: LayoutBottomBarBinding, 14 | ) : Component(), BottomBarService { 15 | 16 | companion object { 17 | private const val TAG = "BottomBar" 18 | } 19 | 20 | override fun onCreate() { 21 | Log.d(TAG, "onCreate: Initializing BottomBar") 22 | binding.textBottom.text = getString(R.string.bottom) 23 | } 24 | 25 | override fun onStart() { 26 | Log.d(TAG, "onStart: BottomBar started") 27 | } 28 | 29 | override fun onResume() { 30 | Log.d(TAG, "onResume: BottomBar resumed") 31 | } 32 | 33 | override fun onPause() { 34 | Log.d(TAG, "onPause: BottomBar paused") 35 | } 36 | 37 | override fun onStop() { 38 | Log.d(TAG, "onStop: BottomBar stopped") 39 | } 40 | 41 | override fun onDestroy() { 42 | Log.d(TAG, "onDestroy: BottomBar destroyed") 43 | } 44 | 45 | override fun sayHello(content: String) { 46 | Log.d(TAG, "BottomBar received message: $content") 47 | } 48 | } 49 | 50 | interface BottomBarService : Service { 51 | fun sayHello(content: String) 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/andy/modules/ui/ContentLayout.kt: -------------------------------------------------------------------------------- 1 | package com.andy.modules.ui 2 | 3 | import android.util.Log 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.andy.modularization.Component 6 | import com.andy.modularization.getString 7 | import com.andy.modules.R 8 | import com.andy.modules.databinding.LayoutContentMainBinding 9 | 10 | class ContentLayout( 11 | override val activity: AppCompatActivity, 12 | private val binding: LayoutContentMainBinding, 13 | ) : Component() { 14 | 15 | companion object { 16 | private const val TAG = "Content" 17 | } 18 | 19 | override fun onCreate() { 20 | Log.d(TAG, "onCreate: Initializing Content component") 21 | binding.textContent.text = getString(R.string.content) 22 | } 23 | 24 | override fun onStart() { 25 | Log.d(TAG, "onStart: Content component started") 26 | } 27 | 28 | override fun onResume() { 29 | Log.d(TAG, "onResume: Content component resumed") 30 | } 31 | 32 | override fun onPause() { 33 | Log.d(TAG, "onPause: Content component paused") 34 | } 35 | 36 | override fun onStop() { 37 | Log.d(TAG, "onStop: Content component stopped") 38 | } 39 | 40 | override fun onDestroy() { 41 | Log.d(TAG, "onDestroy: Content component destroyed") 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/andy/modules/ui/TitleBar.kt: -------------------------------------------------------------------------------- 1 | package com.andy.modules.ui 2 | 3 | import android.util.Log 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.andy.modularization.Component 6 | import com.andy.modularization.ServiceManager 7 | import com.andy.modularization.getString 8 | import com.andy.modularization.holderId 9 | import com.andy.modules.R 10 | import com.andy.modules.databinding.LayoutTitleBarBinding 11 | 12 | class TitleBar( 13 | override val activity: AppCompatActivity, 14 | private val binding: LayoutTitleBarBinding, 15 | ) : Component() { 16 | 17 | companion object { 18 | private const val TAG = "TitleBar" 19 | } 20 | 21 | override fun onCreate() { 22 | Log.d(TAG, "onCreate: Initializing TitleBar component") 23 | binding.textTitle.text = getString(R.string.title) 24 | // It is important to note that the generic parameter 25 | // for ServiceManager.getService 26 | // must be the concrete class name, not the interface. 27 | // Otherwise, the corresponding service cannot be found. 28 | val service = ServiceManager.getService(holderId) 29 | service?.sayHello("Hello from TitleBar") 30 | } 31 | 32 | override fun onStart() { 33 | Log.d(TAG, "onStart: TitleBar component started") 34 | } 35 | 36 | override fun onResume() { 37 | Log.d(TAG, "onResume: TitleBar component resumed") 38 | } 39 | 40 | override fun onPause() { 41 | Log.d(TAG, "onPause: TitleBar component paused") 42 | } 43 | 44 | override fun onStop() { 45 | Log.d(TAG, "onStop: TitleBar component stopped") 46 | } 47 | 48 | override fun onDestroy() { 49 | Log.d(TAG, "onDestroy: TitleBar component destroyed") 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_bottom_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_title_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyhaha/componentFramework/81f705f876afae4123e4493cac8e4cf34cb38e7d/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/navigation/nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 17 | 18 | 23 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/values-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 48dp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-v23/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-w1240dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 200dp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values-w600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 48dp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF000000 4 | #FFFFFFFF 5 | #F5F5F5"> 6 | #FF0000 7 | #B22222 8 | #F5F5DC 9 | #FF4500 10 | #1E90FF 11 | #00BFFF 12 | #32CD32 13 | #66FF66 14 | #7FFFAA 15 | #FFD700 16 | #9B59B6 17 | #FF8C00 18 | #00FFFF 19 | #FF1493 20 | #000080 21 | #ADD8E6 22 | #E6E6FA 23 | #D3D3D3 24 | #C0C0C0 25 | #A9A9A9 26 | #808080 27 | #696969 28 | #FFD700 29 | #FFF8DC 30 | #FFFAF0 31 | #FDF5E6 32 | #F5DEB3 33 | #FFE4B5 34 | #FFA500 35 | #FFEFD5" 36 | #FFEBCD"> 37 | #FFDEAD"> 38 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | modules 3 | Settings 4 | 5 | First Fragment 6 | Second Fragment 7 | Next 8 | Previous 9 | TitleBar component 10 | Content component 11 | BottomBar component 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 |