{"id":21990099,"url":"https://github.com/skyhacker2/modularizationwithdagger2","last_synced_at":"2026-05-09T05:33:49.407Z","repository":{"id":148897772,"uuid":"239141441","full_name":"skyhacker2/modularizationwithdagger2","owner":"skyhacker2","description":"android-modularization-with-dagger2","archived":false,"fork":false,"pushed_at":"2020-02-08T17:12:48.000Z","size":305,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-28T08:55:36.780Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skyhacker2.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-08T14:01:44.000Z","updated_at":"2020-02-08T17:12:51.000Z","dependencies_parsed_at":null,"dependency_job_id":"f1490c9c-949e-4523-8c81-fa0cce702821","html_url":"https://github.com/skyhacker2/modularizationwithdagger2","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyhacker2%2Fmodularizationwithdagger2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyhacker2%2Fmodularizationwithdagger2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyhacker2%2Fmodularizationwithdagger2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyhacker2%2Fmodularizationwithdagger2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skyhacker2","download_url":"https://codeload.github.com/skyhacker2/modularizationwithdagger2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245048795,"owners_count":20552569,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-29T19:37:12.720Z","updated_at":"2025-09-16T13:18:37.767Z","avatar_url":"https://github.com/skyhacker2.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 使用Dagger2对Android工程进行组件化\n\n网上有很多组件化的框架，可以把组件之间的耦合解除了，但是项目却会和某一款组件化框架成了**强耦合**\n\n如果不想依赖某一个组件化框架，有没有方法在目前的项目上进行组件化？\n\n组件化的App基本架构如下图所示：\n\n![image](./images/组件化基本架构.png)\n\n1. App是一个壳工程，依赖component1/component2/component3/...\n2. 打包时，可以把某一个组件的依赖移除，不影响编译（gradle脚本里面注释掉implementation）。\n3. 组件之间不之间依赖。\n\n## 组件之间的通讯\n\n无论哪种组件化方式，都需要一个中间者来连接每个组件。这个中间者就是`ComponentManger`。\n\n`ComponentManger`在`Navigation`模块里面，然后每个组件依赖`Navigation`。\n\n另外有一个`Export-API`的模块，每个组件需要暴露给其他组件的接口都定义在这里。\n\n如果一个组件需要调用另外一个组件，大概是下面这个样子。\n\n```\nComponentLogin loginComponent = ComponentManager.component(ComponentLogin.class);\nif (loginComponent != null) {\n    loginComponent.goToLogin(HomeActivity.this);\n} else {\n    Toast.makeText(HomeActivity.this, \"No Component A\", Toast.LENGTH_SHORT).show();\n}\n```\n\n`ComponentHome`通过`ComponentManager`拿到`ComponentLogin`接口，然后跳转到登录界面。\n\n因为`ComponentLogin`可能是没有的，所以调用组件接口的时候都需要判空。\n\n这样`ComponentHome`组件可以不关心`ComponentLogin`的实现，也不会引用到`ComponentLogin`里面的一些内部类。\n\n## 组件怎样注册到ComponentManager里面？\n从依赖图来看，`Navigation`并不依赖组件，只依赖组件暴露的接口`Export-API`，好像也只能用反射来创建类了。\n\n定义一个`ComponentResolver`接口，只有一个接口，返回一个`Component`\n```\npublic interface ComponentResolver\u003cT extends IComponent\u003e {\n    T getComponent();\n}\n```\n\n这里用了Dagger2的Multibinding，把`ComponentResolver`对象放到一个map里面。key是`Component`的`className`，这里用`ComponentResolver`来返回对应的组件，是为了懒创建`Component`。\n\n```\n@Module\npublic class ComponentModule {\n\n    Map\u003cString, Object\u003e componentObjectMap = new HashMap\u003c\u003e();\n\n    @Provides\n    @ComponentScope\n    @IntoMap\n    @ClassKey(ComponentLogin.class)\n    public ComponentResolver provideLoginComponentResolver() {\n        return new ComponentResolver\u003cComponentLogin\u003e() {\n            @Override\n            public ComponentLogin getComponent() {\n                return ComponentModule.this.getComponent(\"io.github.skyhacker2.component_a.component.ComponentLoginImpl\");\n            }\n        };\n    }\n\n    // 新增一个组件增加一个Provider\n\n    private \u003cT\u003e T getComponent(String className) {\n        try {\n            if (componentObjectMap.get(className) != null) {\n                return (T) componentObjectMap.get(className);\n            }\n            Class clasz = Class.forName(className);\n            T o = (T) clasz.newInstance();\n            componentObjectMap.put(className, o);\n            return o;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        return null;\n    }\n}\n```\n\n在App初始化`ComponentManager`，构建组件的依赖图。\n\n```\n@Component(modules = {ComponentModule.class})\n@ComponentScope\npublic interface ComponentsComponent {\n    Map\u003cClass\u003c?\u003e, ComponentResolver\u003e componentMap();\n}\n```\n\n```\npublic class App extends Application {\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        initComponentDependencies();\n\n        initComponents();\n    }\n\n    private void initComponentDependencies() {\n        ComponentManager.init(DaggerComponentsComponent.builder()\n                .componentModule(new ComponentModule()).build()\n                .componentMap());\n    }\n\n    private void initComponents() {\n\n        ComponentAccount componentAccount = ComponentManager.component(ComponentAccount.class);\n        if (componentAccount != null) {\n            componentAccount.init(this);\n        }\n\n    }\n}\n```\n`ComponentManager`的基本实现\n```\npublic class ComponentManager {\n    private static Map\u003cClass\u003c?\u003e, ComponentResolver\u003e sComponentMap;\n\n    public static void init(Map\u003cClass\u003c?\u003e, ComponentResolver\u003e componentMap) {\n        sComponentMap = componentMap;\n    }\n\n    public static \u003cT\u003e T component(Class\u003c? extends IComponent\u003e clasz) {\n        try {\n            return (T) sComponentMap.get(clasz).getComponent();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        return null;\n    }\n}\n```\n\nDemo的结构图：\n![](images/demo_modules.png)\n\n1. App工程负责组装，初始化组件，跳转到HomeComponent。\n2. HomeComponent首页，通过AccountComponent监听用户登录状态，可以跳转到LoginComponent。\n3. LoginComponent是用户登录的界面，底层通过AccountComponent来实现登录逻辑。\n4. AccountComponent是业务组件，没有界面，负责管理用户状态。\n\nApp的依赖：\n![](images/demo_app_deps.png)\n\n1. 不需要某一个组件，就把对应的implementation注释掉。\n2. 新增一个组件，需要改2个模块，`export-api`和`navigation`。\n3. 组件暴露的接口要尽量少，把复杂的逻辑写在自身里面。\n\n\n## 缺点也很明显\n1. 组件无法编译时确定，用反射创建。\n2. 单独运行某一个组件需要新建单独test工程。","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskyhacker2%2Fmodularizationwithdagger2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskyhacker2%2Fmodularizationwithdagger2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskyhacker2%2Fmodularizationwithdagger2/lists"}