zoukankan      html  css  js  c++  java
  • Android组件化搭建

    什么是组件化

    为了降低项目耦合性,在Android工程中如何实施,目前有两种途径,也是两大流派,一个是组件化,一个是插件化。在这里只介绍组件化,插件化暂不介绍
    正常的APP只有一个application的module和多个libary的module,而组件化开发是为了多个module都可以是application单独运行,发布时在合并。

    代码解耦

    APP:作为主的application的入口,主要作用是了初始化项目的第三方库、欢迎页和主页。

    组件:拆分的业务模块,这种module是一个完整的功能模块,组件可以有多个,具体划分根据业务情况进行划分。

    公用库:基础库library,这些代码被其他组件直接引用,也可以创建一个module专门放资源的库。

    模块通信

    目前使用的是阿里的ARouter进行模块的通信,使用URL进行跳转,达到主项目和组件、组件与组件之间不能直接使用类的相互引用来进行数据交互效果。详细使用,请自行查看github项目或者google,这里只介绍简单介绍:

    1、添加注解
    // 在支持路由的页面上添加注解(必选)
    // 这里的路径需要注意的是至少需要有两级,/xx/xx
    @Route(path = "/test/activity")
    public class YourActivity extend Activity {
        ...
    }
    
    2、初始化SDK
    if (isDebug()) {           // 这两行必须写在init之前,否则这些配置在init过程中将无效
        ARouter.openLog();     // 打印日志
        ARouter.openDebug();   // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
    }
    ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化
    
    3、发起路由操作
    ARouter.getInstance().build("/test/activity").navigation();
    
    详细使用

    1、在global.gradle定义一个参数

    ext {
        isLibrary = true //false:application;true:library
    }
    

    注:global.gradle是全局定义版本库文件

    2、在各业务组件module的build.gradle

    if (rootProject.ext.isLibrary) {
        apply plugin: 'com.android.library'
    } else {
        apply plugin: 'com.android.application'
    }
    
    android {
        defaultConfig {
            if (!rootProject.ext.isLibrary) {
                applicationId "自己的applicationId"
            }
        }
        
        sourceSets {
            main {
                if (rootProject.ext.isLibrary) {
                    manifest.srcFile 'src/main/AndroidManifest.xml'
                } else {
                    manifest.srcFile 'src/main/module/AndroidManifest.xml'
                }
            }
        }
    }
    
    

    3、当业务module当成一个library,需要实现原先Application类中功能,可以使用委托方式实现。

    a、先定义一个IModuleConfig接口,主要实现app生命周期的管理和activity回收管理

    public interface IModuleConfig {
        void injectAppLifecycle(Context context, List<IAppLife> lifeList);
    
        void injectActivityLifecycle(Context context, List<Application.ActivityLifecycleCallbacks> callbacksList);
    
    }
    

    b、定义IAppLife接口,实现Application相关类功能

    public interface IAppLife {
        void attachBaseContext(Context base);
    
        void onCreate(BaseApp application);
    
        void onTerminate(BaseApp application);
    
        void onTrimMemory(int level);
    
        void onLowMemory();
    }
    

    c、在业务module的library里的AndroidManifest.xml配置IModuleConfig

        <meta-data
            android:name="业务模块包名的实现Application类"
            android:value="IModuleConfig" />
    

    d、解析配置IModuleConfig业务module的Application类

    public final class ManifestParser {
        private static final String MODULE_VALUE = "IModuleConfig";
    
        private final Context context;
    
        public ManifestParser(Context context) {
            this.context = context;
        }
    
        public List<IModuleConfig> parse() {
            List<IModuleConfig> modules = new ArrayList<>();
            try {
                ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
                if (appInfo.metaData != null) {
                    for (String key : appInfo.metaData.keySet()) {
                        if (MODULE_VALUE.equals(appInfo.metaData.get(key))) {
                            modules.add(parseModule(key));
                        }
                    }
                }
            } catch (PackageManager.NameNotFoundException e) {
                throw new RuntimeException("解析Application失败", e);
            }
    
            return modules;
        }
    
        private static IModuleConfig parseModule(String className) {
            Class<?> clazz;
            try {
                clazz = Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new IllegalArgumentException(e);
            }
    
            Object module;
            try {
                module = clazz.newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            return (IModuleConfig) module;
        }
    }
    

    e、实现IAppLife的具体类

    public class ApplicationDelegate implements IAppLife {
        private List<IModuleConfig> configList;
        private List<IAppLife> appLifeList;
        private List<Application.ActivityLifecycleCallbacks> callbacksList;
    
    
        public ApplicationDelegate() {
            appLifeList = new ArrayList<>();
            callbacksList = new ArrayList<>();
        }
    
        @Override
        public void attachBaseContext(Context base) {
            ManifestParser manifestParser = new ManifestParser(base);
            configList = manifestParser.parse();
            if (configList != null && configList.size() > 0) {
                for (IModuleConfig configModule : configList) {
                    configModule.injectAppLifecycle(base, appLifeList);
                    configModule.injectActivityLifecycle(base, callbacksList);
                }
            }
            if (appLifeList != null && appLifeList.size() > 0) {
                for (IAppLife life : appLifeList) {
                    life.attachBaseContext(base);
                }
            }
        }
    
        @Override
        public void onCreate(BaseApp application) {
            Ln.d("ApplicationDelegate onCreate:%s", appLifeList.size());
            if (appLifeList != null && appLifeList.size() > 0) {
                for (IAppLife life : appLifeList) {
                    life.onCreate(application);
                }
            }
            if (callbacksList != null && callbacksList.size() > 0) {
                for (Application.ActivityLifecycleCallbacks life : callbacksList) {
                    application.registerActivityLifecycleCallbacks(life);
                }
            }
        }
    
        @Override
        public void onTerminate(BaseApp application) {
            if (appLifeList != null && appLifeList.size() > 0) {
                for (IAppLife life : appLifeList) {
                    life.onTerminate(application);
                }
            }
            if (callbacksList != null && callbacksList.size() > 0) {
                for (Application.ActivityLifecycleCallbacks life : callbacksList) {
                    application.unregisterActivityLifecycleCallbacks(life);
                }
            }
        }
    
        @Override
        public void onTrimMemory(int level) {
            if (appLifeList != null && appLifeList.size() > 0) {
                for (IAppLife life : appLifeList) {
                    life.onTrimMemory(level);
                }
            }
        }
    
        @Override
        public void onLowMemory() {
            if (appLifeList != null && appLifeList.size() > 0) {
                for (IAppLife life : appLifeList) {
                    life.onLowMemory();
                }
            }
        }
    }
    

    f、公用的Application类

    public class BaseApplication extends BaseApp {
        private static BaseApplication instance;
        private ApplicationDelegate applicationDelegate;
    
        public static BaseApplication getInstance() {
            return instance;
        }
    
    
        @Override
        protected void attachBaseContext(Context base) {
            super.attachBaseContext(base);
            Ln.init(this);
            MultiDex.install(this);
            applicationDelegate = new ApplicationDelegate();
            applicationDelegate.attachBaseContext(base);
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            if (!HostUtils.isInMainProcess(this)) return;
            // 这两行必须写在init之前,否则这些配置在init过程中将无效
            ARouter.openLog();     // 打印日志
            Ln.d("BaseApplication:%s", isDebug);
            ARouter.openDebug();
            ARouter.init(this);
            instance = this;
            applicationDelegate.onCreate(this);
            Ln.d("BaseApplication applicationDelegate.");
        }
    
    
        @Override
        public void onTerminate() {
            super.onTerminate();
            applicationDelegate.onTerminate(this);
        }
    
        @Override
        public void onLowMemory() {
            super.onLowMemory();
            applicationDelegate.onLowMemory();
        }
    
        @Override
        public void onTrimMemory(int level) {
            super.onTrimMemory(level);
            applicationDelegate.onTrimMemory(level);
        }
    }
    

    注:module1 和 module2 分别都依赖了 common,不会导致 library 重复依赖。

    module为library的填坑

    1、资源ID报无法访问的错误,因为在library中,资源ID是一个变量,而不是常量,在switch中、ButterKnife、注解使用资源ID都会提示错误。switch报错解决办法是用if-else,而注解解决办法使用string参数,注解实现类中根据这个string参数读取资源。

    2、使用Dagger2后,无法自动生成相关的Dagger类,解决办法:

    定义一个注解
    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PerApplication {
    }
    
    在Dagger接口类上加上注解
    @PerApplication
    @Component(modules = {NetworkModule.class})
    @Singleton
    public interface AppComponent {
    
    }
    

    3、资源冲突问题,当分别开发模块时,容易出资源重复命名的问题,可以在build.gradle中设置

    resourcePrefix "module1_"
    
  • 相关阅读:
    Linux下并发网络设计之I/O复用
    嵌入式系统 Boot Loader
    linux下curl编程
    c语言中-----分配内存函数
    关于typedef之四种用途 和 两个陷进
    Libcurl安装及编译
    linux线程之pthread_join和pthread_detach
    Linux系统源码安装过程中的prefix选项
    linux之线程之互斥
    linux之线程
  • 原文地址:https://www.cnblogs.com/fomin/p/8534163.html
Copyright © 2011-2022 走看看