当前位置:   article > 正文

android library依赖 aar_Android-模块化、组件化、插件化、热修复-组件化工程构建+页面路由多种方式实践...

android多个模块间 依赖 arr api

上一篇MonkeyLei:Android-模块化、组件化、插件化、热修复-组件化一下试试 我们大概尝试了下一个Modulelibrary与application切换。这也是为为后续的继续做准备...今天我们就尝试自己搭建一个组件化工程,并初步做一个页面的跳转(组件间的通信其中一个点),后续还会完善组件间相互通信的方式。

工程实践完后,我会设置下Module的状态(Library和Module直接做切换),然后单独运行App或者Module,如果都没问题,这才能保证组件之间无耦合!!!

工程走起!

cbf929ddd3e5aefdfd11aea8e6babf2b.png

1. 公共库Module一般作为Library使用。而组件Module我们可以来回切换,但是我们新建Module的时候还是如下方式(保证有启动的manifest配置):

57d7892b0367db709e7252b9327c38e9.png

f4b012711bd05efab7ea4e348a022284.png

2. 然后按照上一篇学到的知识,代码配置下Module的Library和Application切换;然而为了方便统一管理App基础信息,各个Module的版本信息,以及第三方依赖库的版本信息等,我们项目根目录下新建一个config.gradle,专门用来配置:

config.gradle

  1. /**
  2. * 全局统一配置
  3. */
  4. ext {
  5. /**
  6. * module开关统一声明在此处
  7. * true:module作为application,可单独打包为apk
  8. * false:module作为library,可作为宿主application的组件
  9. */
  10. isLoginModule = false
  11. isPersonalModule = false
  12. /**
  13. * 版本统一管理
  14. */
  15. versions = [
  16. applicationId : "com.skl.zujianhua", // 应用ID
  17. versionCode : 1, // 版本号
  18. versionName : "1.0.0", // 版本名称
  19. compileSdkVersion : 28,
  20. minSdkVersion : 15,
  21. targetSdkVersion : 28,
  22. buildToolsVersion : "29.0.0",
  23. constraintlayoutVersion: "1.1.3",
  24. runnerVersion : "1.0.2",
  25. espressoVersion : "3.0.2",
  26. junitVersion : "4.12",
  27. appcompatVersion : "28.0.0",
  28. arouterApiVersion : "1.5.0",
  29. arouterCompilerVersion : "1.2.2",
  30. ]
  31. dependencies = [
  32. "appcompat" : "com.android.support:appcompat-v7:${versions["appcompatVersion"]}",
  33. "constraintlayout": "com.android.support.constraint:constraint-layout:${versions["constraintlayoutVersion"]}",
  34. "runner" : "com.android.support.test:runner:${versions["runnerVersion"]}",
  35. "espresso_core" : "com.android.support.test.espresso:espresso-core:${versions["espressoVersion"]}",
  36. "junit" : "junit:junit:${versions["junitVersion"]}",
  37. // TODO MD等新增支持库
  38. // //注释处理器
  39. // "support_annotations" : "com.android.support:support-annotations:${versions["annotationsVersion"]}",
  40. // "design" : "com.google.android.material:material:${versions["designVersion"]}",
  41. // TODO 其他公共的依赖都可以配置到这里
  42. // //方法数超过65535解决方法64K MultiDex分包方法
  43. // "multidex" : "androidx.multidex:multidex:2.0.0",
  44. //阿里路由
  45. "arouter_api" : "com.alibaba:arouter-api:${versions["arouterApiVersion"]}",
  46. "arouter_compiler": "com.alibaba:arouter-compiler:${versions["arouterCompilerVersion"]}",
  47. // "arouter_annotation" : "com.alibaba:arouter-annotation:${versions["arouterAnnotationVersion"]}",
  48. //
  49. // //黄油刀
  50. // "butterknife" : "com.jakewharton:butterknife:${versions["butterknifeVersion"]}",
  51. // "butterknife_compiler": "com.jakewharton:butterknife-compiler:${versions["butterknifeVersion"]}"
  52. ]
  53. }

2.1 根目录下的build.gradle下添加config配置:

  apply from: "config.gradle" 

3. 此时我们不想每个Library/Application用到第三方库(比如Butterknife、Arouter、MultiDex等)都去依赖,因此我们新建一个基础模块basemodule: - (Arouter实践过了,所以就一并贴出来算了。不过我们的学习过程一般都是渐进式的,先实现基础工程,模块的构建,完事三方依赖都配置好,切换都测试成功了,然后再开始搞路由!)

重点看下build.gradle配置:

  1. apply plugin: 'com.android.library'
  2. android {
  3. compileSdkVersion 28
  4. buildToolsVersion "29.0.0"
  5. defaultConfig {
  6. minSdkVersion 15
  7. targetSdkVersion 28
  8. versionCode 1
  9. versionName "1.0"
  10. testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  11. javaCompileOptions {
  12. annotationProcessorOptions {
  13. arguments = [AROUTER_MODULE_NAME: project.getName()]
  14. }
  15. }
  16. }
  17. buildTypes {
  18. release {
  19. minifyEnabled false
  20. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  21. }
  22. }
  23. }
  24. dependencies {
  25. implementation fileTree(dir: 'libs', include: ['*.jar'])
  26. // 把implementation 用api代替,它是对外部公开的, 所有其他的module就不需要添加该依赖
  27. api rootProject.ext.dependencies["appcompat"]
  28. api rootProject.ext.dependencies["constraintlayout"]
  29. api rootProject.ext.dependencies["junit"]
  30. api rootProject.ext.dependencies["runner"]
  31. api rootProject.ext.dependencies["espresso_core"]
  32. // //注释处理器,butterknife所必需
  33. // api rootProject.ext.dependencies["support_annotations"]
  34. //
  35. // //MultiDex分包方法
  36. // api rootProject.ext.dependencies["multidex"]
  37. //
  38. // //Material design
  39. // api rootProject.ext.dependencies["design"]
  40. //
  41. // //黄油刀
  42. // api rootProject.ext.dependencies["butterknife"]
  43. // annotationProcessor rootProject.ext.dependencies["butterknife_compiler"]
  44. //Arouter路由
  45. annotationProcessor rootProject.ext.dependencies["arouter_compiler"]
  46. api rootProject.ext.dependencies["arouter_api"]
  47. // api rootProject.ext.dependencies["arouter_annotation"]
  48. }

4. 然后接着我们创建Appliaction模块Login和Personal,这样创建出来就直接配置上了,然后单独可以运行啦,记得都依赖上basemodule - 后续的公共模块都可以放到basemodule中去!

50617d8d1ae651cce96da3010af68077.png

4.1 然后根据之前的知识配置下和Library的切换: - 参数都是根目录/congig.gradle配置的,别忘记了

login/build.gradle

  1. if (Boolean.valueOf(rootProject.ext.isLoginModule)) {
  2. apply plugin: 'com.android.application'
  3. } else {
  4. apply plugin: 'com.android.library'
  5. }
  6. // TODO 虽然依赖了公共库,但是有些配置还是要模块内部自己配置
  7. // apply plugin: 'com.jakewharton.butterknife'
  8. android {
  9. compileSdkVersion 28
  10. buildToolsVersion "29.0.0"
  11. defaultConfig {
  12. // Application模式下设置applicationId
  13. if (Boolean.valueOf(rootProject.ext.isLoginModule)) {
  14. applicationId "com.skl.login"
  15. }
  16. minSdkVersion 15
  17. targetSdkVersion 28
  18. versionCode 1
  19. versionName "1.0"
  20. testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  21. javaCompileOptions {
  22. annotationProcessorOptions {
  23. arguments = [AROUTER_MODULE_NAME: project.getName()]
  24. }
  25. }
  26. }
  27. buildTypes {
  28. release {
  29. minifyEnabled false
  30. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  31. }
  32. }
  33. sourceSets {
  34. main {
  35. if (Boolean.valueOf(rootProject.ext.isLoginModule)) {
  36. manifest.srcFile 'src/main/AndroidManifest.xml'
  37. } else {
  38. // Library模式可以不用配置manifest文件
  39. }
  40. }
  41. }
  42. }
  43. dependencies {
  44. implementation fileTree(dir: 'libs', include: ['*.jar'])
  45. // 公共依赖库
  46. implementation project(path: ':basemodule')
  47. // TODO 虽然依赖了公共库,但是有些配置还是要模块内部自己配置
  48. // //黄油刀
  49. // annotationProcessor rootProject.ext.dependencies["butterknife_compiler"]
  50. //Arouter路由
  51. annotationProcessor rootProject.ext.dependencies["arouter_compiler"]
  52. }

personal/build.gradle

  1. if (Boolean.valueOf(rootProject.ext.isPersonalModule)) {
  2. apply plugin: 'com.android.application'
  3. } else {
  4. apply plugin: 'com.android.library'
  5. }
  6. // TODO 虽然依赖了公共库,但是有些配置还是要模块内部自己配置
  7. // apply plugin: 'com.jakewharton.butterknife'
  8. android {
  9. compileSdkVersion 28
  10. buildToolsVersion "29.0.0"
  11. defaultConfig {
  12. // Application模式下设置applicationId
  13. if (Boolean.valueOf(rootProject.ext.isLoginModule)) {
  14. applicationId "com.skl.personal"
  15. }
  16. minSdkVersion 15
  17. targetSdkVersion 28
  18. versionCode 1
  19. versionName "1.0"
  20. testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  21. javaCompileOptions {
  22. annotationProcessorOptions {
  23. arguments = [AROUTER_MODULE_NAME: project.getName()]
  24. }
  25. }
  26. }
  27. buildTypes {
  28. release {
  29. minifyEnabled false
  30. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  31. }
  32. }
  33. sourceSets {
  34. main {
  35. if (Boolean.valueOf(rootProject.ext.isPersonalModule)) { // apk
  36. manifest.srcFile 'src/main/AndroidManifest.xml'
  37. } else {
  38. // Library模式可以不用配置manifest文件
  39. }
  40. }
  41. }
  42. }
  43. dependencies {
  44. implementation fileTree(dir: 'libs', include: ['*.jar'])
  45. // 公共依赖库
  46. implementation project(path: ':basemodule')
  47. // TODO 虽然依赖了公共库,但是有些配置还是要模块内部自己配置
  48. // //黄油刀
  49. // annotationProcessor rootProject.ext.dependencies["butterknife_compiler"]
  50. //Arouter路由
  51. annotationProcessor rootProject.ext.dependencies["arouter_compiler"]
  52. }

5. 修改下app主模块下的布局,做一个点击按钮事件,分别用来跳转到login和personal页面:

app/activity_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".MainActivity">
  8. <Button
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:onClick="GoLogin"
  12. android:text="跳转到Login界面"
  13. app:layout_constraintLeft_toLeftOf="parent"
  14. app:layout_constraintTop_toTopOf="parent" />
  15. <Button
  16. android:layout_width="wrap_content"
  17. android:layout_height="wrap_content"
  18. android:onClick="GoPersonal"
  19. android:text="跳转到个人信息页面"
  20. app:layout_constraintEnd_toEndOf="parent"
  21. app:layout_constraintTop_toTopOf="parent" />
  22. </android.support.constraint.ConstraintLayout>

MainActivity.java

  1. package com.skl.zujianhua;
  2. import android.support.v7.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import com.alibaba.android.arouter.launcher.ARouter;
  6. public class MainActivity extends AppCompatActivity {
  7. @Override
  8. protected void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. setContentView(R.layout.activity_main);
  11. }
  12. /**
  13. * 跳转到登录页面
  14. *
  15. * @param view
  16. */
  17. public void GoLogin(View view) {
  18. // 跳转方式1: 通过反射
  19. // try {
  20. // Class clazz = Class.forName("com.skl.login.LoginActivity");
  21. // Intent intent = new Intent(this, clazz);
  22. // startActivity(intent);
  23. // // startActivityForResult(intent, 110);
  24. // } catch (ClassNotFoundException e) {
  25. // e.printStackTrace();
  26. // }
  27. // 跳转方式2:每个页面都注册到base模块,由base模块提供跳转服务
  28. // CompomentsService.getiAppComponentHashMap(AppConfig.PAGE_TYPE.LOGIN).launch(this, null);
  29. // 跳转方式3:采用URI方式
  30. // startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("activity://login")));
  31. // 跳转方式4:采用 Arouter
  32. ARouter.getInstance().build("/hl/login")
  33. // .withString("nothing", "Gone with the Wind")
  34. // .withObject("author", Object)
  35. .navigation(this, 110);
  36. }
  37. /**
  38. * 跳转到个人中心
  39. *
  40. * @param view
  41. */
  42. public void GoPersonal(View view) {
  43. // 跳转方式4:采用 Arouter
  44. ARouter.getInstance().build("/ppx/personal")
  45. // .withString("nothing", "Gone with the Wind")
  46. // .withObject("author", Object)
  47. .navigation(this, 110);
  48. }
  49. }

5.1 上面分别列出了四种跳转方式,首先反射的方式,这个要试试哈。记得页面是需要配置到AndroidManifest.xml的哟。

5.2 先说跳转方式3, URI的方式,这个需要配置待跳转页面的scheme、host、action、category信息,然后跳转时根据scheme和host做路由:

login/src/main/AndroidManifest.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.skl.login">
  4. <application
  5. android:allowBackup="true"
  6. android:icon="@mipmap/ic_launcher"
  7. android:label="@string/app_name"
  8. android:roundIcon="@mipmap/ic_launcher_round"
  9. android:supportsRtl="true"
  10. android:theme="@style/AppTheme">
  11. <activity android:name=".LoginActivity">
  12. <!--跳转方式3:提供URI方式-->
  13. <intent-filter>
  14. <action android:name="android.intent.action.VIEW" />
  15. <category android:name="android.intent.category.DEFAULT" />
  16. <category android:name="android.intent.category.BROWSABLE" />
  17. <data android:scheme="activity" />
  18. <data android:host="login" />
  19. </intent-filter>
  20. </activity>
  21. </application>
  22. </manifest>

然后 startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("activity://login")));就可以跳转了啦.....

5.3 接着说跳转方式4 ,ARouter的方式,github地址,上面配置方式都有啦:alibaba/ARouter

照着配置就行,不过要注意我们有basemodule,多个library,so,注意下面这个说明: - javaCompileOptions比较关键,不然你的路由就会报="http://www.baidu.com/link?url=SFoQYEc0VH3o8IZkDe1H0v2W30NKqGHpsDU24PfR5pLn_c7GdXgkmO8moxxq7YGDO8VFzM4u0FFIwpTv25xIgKeKXK3YTN6DS8bTFKQuthy">ARouter there's no route matched

  1. 虽然我们basemodule采用api的方式引入了arouter:
  2. basemodule/build.gradle
  3. //Arouter路由
  4. annotationProcessor rootProject.ext.dependencies["arouter_compiler"]
  5. api rootProject.ext.dependencies["arouter_api"]
  6. 但是其他的Module需要使用的地方同样需要添加如下配置:
  7. login/build.gradle
  8. personal/build.gradle
  9. android {
  10. compileSdkVersion 28
  11. buildToolsVersion "29.0.0"
  12. defaultConfig {
  13. ......
  14. javaCompileOptions {
  15. annotationProcessorOptions {
  16. arguments = [AROUTER_MODULE_NAME: project.getName()]
  17. }
  18. }
  19. }
  20. .....
  21. }
  22. dependencies {
  23. implementation fileTree(dir: 'libs', include: ['*.jar'])
  24. // 公共依赖库
  25. implementation project(path: ':basemodule')
  26. // TODO 虽然依赖了公共库,但是有些配置还是要模块内部自己配置
  27. // //黄油刀
  28. // annotationProcessor rootProject.ext.dependencies["butterknife_compiler"]
  29. // Arouter路由
  30. annotationProcessor rootProject.ext.dependencies["arouter_compiler"]
  31. }

5.3.1 然后我们的login,personal都配置上路由信息,方便路由跳转(其他用法待深入) - 路由配置注意:不同module的路由路径的一级命名不能相同。

4911375943d6846f1057b9e8dac6a59f.png

login/ LoginActivity.java

  1. package com.skl.login;
  2. import android.support.v7.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import com.alibaba.android.arouter.facade.annotation.Route;
  6. @Route(path = "/hl/login")
  7. public class LoginActivity extends AppCompatActivity {
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_login);
  12. }
  13. /**
  14. * 登录 + 可以保存数据到本地(采用sharedpreferences的方式存储)
  15. * TODO 注意:这里为了模拟组件间的接口调用,采用其他方式
  16. * @param view
  17. */
  18. public void logining(View view) {
  19. }
  20. }

personal/PersonalActivity.java

  1. package com.skl.personal;
  2. import android.support.v7.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import com.alibaba.android.arouter.facade.annotation.Route;
  6. @Route(path = "/ppx/personal")
  7. public class PersonalActivity extends AppCompatActivity {
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_personal);
  12. }
  13. /**
  14. * 获取登录页面个人信息并展示
  15. * @param view
  16. */
  17. public void getLoginInfo(View view) {
  18. }
  19. }

然后开始路由前,主模块app下的MainApplication需要初始化路由组件 - 直接文档添加过来稍加处理就行

  1. // ARouter路由初始化
  2. if (BuildConfig.DEBUG) { // These two lines must be written before init, otherwise these configurations will be invalid in the init process
  3. ARouter.openLog(); // Print log
  4. ARouter.openDebug(); // Turn on debugging mode (If you are running in InstantRun mode, you must turn on debug mode! Online version needs to be closed, otherwise there is a security risk)
  5. }
  6. ARouter.init(this); // As early as possible, it is recommended to initialize in the Application

5.3.2 此时就可以进行路由跳转了呀

  1. // 跳转方式4:采用 Arouter
  2. ARouter.getInstance().build("/hl/login")
  3. // .withString("nothing", "Gone with the Wind")
  4. // .withObject("author", Object)
  5. .navigation(this, 110);

6. 最后跳转方式2,这里采用下沉到base模块的方式,各个组件注册到base模块的服务页面,然后由各个模块提供lunch方法。其他模块使用的时候只需要调用base模块的注册的组件对应的lunch方法既可!这个就主要涉及到接口的使用了。

处理方式:6.1 定义IAppComponent接口

  1. package com.skl.basemodule.common_interface;
  2. import android.app.Application;
  3. import android.content.Context;
  4. /**
  5. * 组件Application初始化时需要实现的接口
  6. */
  7. public interface IAppComponent {
  8. void initialize(Application app);
  9. void launch(Context context, String extra);
  10. }

6.2 此时就需要各个模块添加Application类(basemodule纯粹是一个library,不参与),然后统一由主Application去调用各个模块的initialize方法(这个时候模块Library要注意,如果不涉及到单独运行,不用去配置application,不然运行报错啦),如下:

f77c10caa9c2fb7a0c8c1270dd7129c9.png

9de6d2e9b7590737ac73cb71cced2416.png

6.3 主模块此时由于不能直接与其他模块产生耦合,所以采用反射的方式去初始化各个组件的Application

实现之前先定义一个basemodule/AppConfig.java用来存储组件信息: - 我采用的接口和其他人略有不同,主要是方便到时候根据枚举进行页面注册,同时根据枚举进行页面跳转,后面就知道了

  1. package com.skl.basemodule;
  2. import java.util.HashMap;
  3. public class AppConfig {
  4. public enum PAGE_TYPE {
  5. LOGIN, PERSONAL
  6. }
  7. /**
  8. * 组件集合
  9. */
  10. public static HashMap<PAGE_TYPE, String> COMPONENTS = new HashMap<PAGE_TYPE, String>() {
  11. {
  12. // 登录页面
  13. put(PAGE_TYPE.LOGIN, "com.skl.login.LoginApplication");
  14. // 登录页面
  15. put(PAGE_TYPE.PERSONAL, "com.skl.login.PersonalApplication");
  16. }
  17. };
  18. }

app/src/main/xxxxx/MainApplication.java - MainApplication也实现组件通信的接口IAppComponent,其他页面有可能也需要跳转到主页面

  1. package com.skl.zujianhua;
  2. import android.app.Application;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.os.Build;
  6. import android.os.Bundle;
  7. import com.alibaba.android.arouter.launcher.ARouter;
  8. import com.skl.basemodule.AppConfig;
  9. import com.skl.basemodule.common_interface.IAppComponent;
  10. import java.util.Map;
  11. public class MainApplication extends Application implements IAppComponent {
  12. @Override
  13. public void onCreate() {
  14. super.onCreate();
  15. initialize(this);
  16. }
  17. @Override
  18. public void initialize(Application app) {
  19. // 遍历所有的组件的Application类,依次用反射的方式实现组件初始化和注册
  20. for(Map.Entry<AppConfig.PAGE_TYPE, String> entry: AppConfig.COMPONENTS.entrySet())
  21. {
  22. try {
  23. Class classz = Class.forName(entry.getValue());
  24. Object object = classz.newInstance();
  25. // 实例化后,调用各个组件的initialize方法(init会实现组件的注册)
  26. if (object instanceof IAppComponent) {
  27. ((IAppComponent) object).initialize(app);
  28. }
  29. } catch (IllegalAccessException e) {
  30. e.printStackTrace();
  31. } catch (InstantiationException e) {
  32. e.printStackTrace();
  33. } catch (ClassNotFoundException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. // ARouter路由初始化
  38. if (BuildConfig.DEBUG) { // These two lines must be written before init, otherwise these configurations will be invalid in the init process
  39. ARouter.openLog(); // Print log
  40. ARouter.openDebug(); // Turn on debugging mode (If you are running in InstantRun mode, you must turn on debug mode! Online version needs to be closed, otherwise there is a security risk)
  41. }
  42. ARouter.init(this); // As early as possible, it is recommended to initialize in the Application
  43. }
  44. @Override
  45. public void launch(Context context, String extra) {
  46. Intent intent = new Intent(context, MainActivity.class);
  47. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  48. Bundle bundle = new Bundle();
  49. if (null != extra && !extra.equals(""))
  50. bundle.putString("extra_data", extra);
  51. context.startActivity(intent, bundle);
  52. } else {
  53. if (null != extra && !extra.equals(""))
  54. intent.putExtra("extra_data", extra);
  55. context.startActivity(intent);
  56. }
  57. }
  58. }

6.4 为了实现组件Application初始化,并且能全局存储组件的信息,我们定一个组件服务类CompomentsService.java - 注册组件时根据枚举存储组件信息,同时提供了获取组件(类型就是通信接口IAppComponent )

  1. package com.skl.basemodule;
  2. import com.skl.basemodule.common_interface.IAppComponent;
  3. import java.util.HashMap;
  4. /**
  5. * 组件初始化时都注册到这个服务里面
  6. */
  7. public class CompomentsService {
  8. private static HashMap<AppConfig.PAGE_TYPE, IAppComponent> iAppComponentHashMap = new HashMap<>();
  9. public static void setiAppComponentHashMap(AppConfig.PAGE_TYPE componentName, IAppComponent iAppComponent){
  10. iAppComponentHashMap.put(componentName, iAppComponent);
  11. }
  12. public static IAppComponent getiAppComponentHashMap(AppConfig.PAGE_TYPE componentName){
  13. if (iAppComponentHashMap.containsKey(componentName)){
  14. return iAppComponentHashMap.get(componentName);
  15. }
  16. return null;
  17. }
  18. }

6.5 然后此时我们就可以把login、personal模块初始化并注册了:

login/ LoginApplication.java - 里面有注释,相对好理解

  1. package com.skl.login;
  2. /**
  3. * 单独运行时需要的话可以配置到AndroidManifest,不需要就不要配置,不然运行报错
  4. */
  5. import android.app.Application;
  6. import android.content.Context;
  7. import android.content.Intent;
  8. import android.os.Build;
  9. import android.os.Bundle;
  10. import com.skl.basemodule.AppConfig;
  11. import com.skl.basemodule.CompomentsService;
  12. import com.skl.basemodule.common_interface.IAppComponent;
  13. public class LoginApplication extends Application implements IAppComponent {
  14. /**
  15. * 单独作为Application时会走该方法
  16. */
  17. @Override
  18. public void onCreate() {
  19. super.onCreate();
  20. // TODO 单独运行时没有需要可以不用调用
  21. initialize(this);
  22. }
  23. /**
  24. * App的Application注册组件时会调用initialize方法!
  25. *
  26. * @param app
  27. */
  28. @Override
  29. public void initialize(Application app) {
  30. // 注册自己到组件服务
  31. CompomentsService.setiAppComponentHashMap(AppConfig.PAGE_TYPE.LOGIN, this);
  32. }
  33. /**
  34. * 启动自己
  35. *
  36. * @param context
  37. * @param extra
  38. */
  39. @Override
  40. public void launch(Context context, String extra) {
  41. Intent intent = new Intent(context, LoginActivity.class);
  42. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  43. Bundle bundle = new Bundle();
  44. if (null != extra && !extra.equals(""))
  45. bundle.putString("extra_data", extra);
  46. context.startActivity(intent, bundle);
  47. } else {
  48. if (null != extra && !extra.equals(""))
  49. intent.putExtra("extra_data", extra);
  50. context.startActivity(intent);
  51. }
  52. }
  53. }

personal/PersonalApplication.java

  1. package com.skl.personal;
  2. import android.app.Application;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.os.Build;
  6. import android.os.Bundle;
  7. import com.skl.basemodule.AppConfig;
  8. import com.skl.basemodule.CompomentsService;
  9. import com.skl.basemodule.common_interface.IAppComponent;
  10. /**
  11. * 单独运行时需要的话可以配置到AndroidManifest,不需要就不要配置,不然运行报错
  12. */
  13. public class PersonalApplication extends Application implements IAppComponent {
  14. /**
  15. * 单独作为Application时会走该方法
  16. */
  17. @Override
  18. public void onCreate() {
  19. super.onCreate();
  20. // TODO 单独运行时没有需要可以不用调用
  21. initialize(this);
  22. }
  23. /**
  24. * App的Application注册组件时会调用initialize方法!
  25. *
  26. * @param app
  27. */
  28. @Override
  29. public void initialize(Application app) {
  30. // 注册自己到组件服务
  31. CompomentsService.setiAppComponentHashMap(AppConfig.PAGE_TYPE.PERSONAL, this);
  32. }
  33. /**
  34. * 启动自己
  35. *
  36. * @param context
  37. * @param extra
  38. */
  39. @Override
  40. public void launch(Context context, String extra) {
  41. Intent intent = new Intent(context, PersonalActivity.class);
  42. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  43. Bundle bundle = new Bundle();
  44. if (null != extra && !extra.equals(""))
  45. bundle.putString("extra_data", extra);
  46. context.startActivity(intent, bundle);
  47. } else {
  48. if (null != extra && !extra.equals(""))
  49. intent.putExtra("extra_data", extra);
  50. context.startActivity(intent);
  51. }
  52. }
  53. }

7. 完事了我们就可以采用下沉到公共模块的方式来实现页面跳转 - 枚举方便我们清晰知道要跳转到哪里。相比Arouter,还是不安逸。但是了解一下也好鸭.....

  1. // 跳转方式2:每个页面都注册到base模块,由base模块提供跳转服务
  2. CompomentsService.getiAppComponentHashMap(AppConfig.PAGE_TYPE.LOGIN).launch(this, null);

8. 大概一个组件化工程目前一天两天的学习过程和实践就是酱紫。。。还有很多我们可以去联想和实践的,比如页面之间的相互通信,主动回调通知刷新等。以及Eventbus相关集成,如何集成的更好,其他的路由通信方式等等一堆问题!。。。。

组件化如果产生了耦合就尴尬了,这就是设计的魅力!

附上工程地址吧: https://gitee.com/heyclock/doc/tree/master/组件化

一些个参考:可以多像网友学习,但是还是要有自己的想法,哪怕改成自己顺手都是可以的,可能会实践的不好也没关系,至少大的方向应该是对的了。。

https://blog.csdn.net/jiyidehao/article/details/85390370

Android组件化

https://blog.csdn.net/sziitjin/article/details/97761949

Android组件化框架搭建

https://blog.csdn.net/hailong0529/article/details/89392064

https://blog.csdn.net/gaolei1201/article/details/77601027 - 如何跳转页面的方式

alibaba/ARouter

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/331662
推荐阅读
相关标签
  

闽ICP备14008679号