| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Android组件化学习,微信小程序趋势及前景 -> 正文阅读 |
|
[移动开发]Android组件化学习,微信小程序趋势及前景 |
} } } } 由于library是不需要 Application 和启动Activity页,所以我们要区分这个文件,应用manifest指定的路径没有特定,随意找个路径创建即可。在应用AndroidManifest.xml里我们要设置启动页: <manifest xmlns:android=“http://schemas.android.com/apk/res/android” package=“com.sun.biz_home”> <application android:allowBackup=“true” android:label="@string/home_app_name" android:supportsRtl=“true” android:theme="@style/home_AppTheme"> library 的 AndroidManifest.xml 不需要这些: <manifest xmlns:android=“http://schemas.android.com/apk/res/android” package=“com.sun.biz_home”> gradle 依赖 module 的方式主要有两种:
一般来说我们只需要使用 implementation 即可,api 是会造成项目编译时间变长,而且会引入该模块不需要的功能,代码之间耦合变得严重了。不过 module_common 是统一了基础组件版本的公共库,所有组件都应需要依赖它并拥有基础组件的能力,所以基本每个业务组件和业务基础组件都应该依赖公共库: dependencies { implementation project(’:module_common’) } 而 common 组件依赖基础组件应该是用 api,因为把基础组件的能力传递给上层业务组件: dependencies { api project(’:module_base’) api project(’:module_util’) } 多工程方案多工程就是每个组件都是一个工程,例如创建一个工程后 app 作为壳组件,它依赖 biz_home 运行,因此不需要 isModule 来控制独立调试,它本身就是一个工程可以独立调试。 多工程的利弊就是和单工程相反的:
多工程组件依赖需要用到maven仓库。把每个组件的aar上传到公司内网的maven仓库,然后像这样去依赖: implementation ‘com.xxx.xxx:module_common:1.0.0’ 我们在学习组件化的过程中可以搭建一个maven仓库并把aar上传到我们自己搭建的maven仓库,这里是一篇搭建maven仓库和上传aar的介绍。注意一点,我们在开发阶段用snapshot快照版本不更改版本号上传,在发布release正式版时增加版本号并上传。 我们把三方库统一放到 config.gradle 内管理: ext { dependencies = [ “glide”: “com.github.bumptech.glide:glide:4.12.0”, “glide-compiler”: “com.github.bumptech.glide:compiler:4.12.0”, “okhttp3”: “com.squareup.okhttp3:okhttp:4.9.0”, “retrofit”: “com.squareup.retrofit2:retrofit:2.9.0”, “retrofit-converter-gson” : “com.squareup.retrofit2:converter-gson:2.9.0”, “retrofit-adapter-rxjava2” : “com.squareup.retrofit2:adapter-rxjava2:2.9.0”, “rxjava2”: “io.reactivex.rxjava2:rxjava:2.2.21”, “arouter”: “com.alibaba:arouter-api:1.5.1”, “arouter-compiler”: “com.alibaba:arouter-compiler:1.5.1”, // our lib “module_util”: “com.sun.module:module_util:1.0.0”, “module_common”: “com.sun.module:module_common:1.0.0”, “module_base”: “com.sun.module:module_base:1.0.0”, “fun_splash”: “com.sun.fun:fun_splash:1.0.0”, “fun_share”: “com.sun.fun:fun_share:1.0.0”, “export_biz_home”: “com.sun.export:export_biz_home:1.0.0”, “export_biz_me”: “com.sun.export:export_biz_me:1.0.0”, “export_biz_msg”: “com.sun.export:export_biz_msg:1.0.0”, “biz_home”: “com.sun.biz:biz_home:1.0.0”, “biz_me”: “com.sun.biz:biz_me:1.0.0”, “biz_msg”: “com.sun.biz:biz_msg:1.0.0” ] } 这样方便版本统一管理, 然后在根目录的 build.gradle 内导入: apply from: ‘config.gradle’ 最后在各自的模块引入依赖,比如在 module_common 中这么引入依赖即可。 dependencies { api rootProject.ext.dependencies[“arouter”] kapt rootProject.ext.dependencies[“arouter-compiler”] api rootProject.ext.dependencies[“glide”] api rootProject.ext.dependencies[“okhttp3”] api rootProject.ext.dependencies[“retrofit”] api rootProject.ext.dependencies[“retrofit-converter-gson”] api rootProject.ext.dependencies[“retrofit-adapter-rxjava2”] api rootProject.ext.dependencies[“rxjava2”] api rootProject.ext.dependencies[“module_util”] api rootProject.ext.dependencies[“module_base”] } 个人觉得多工程适合"很大"的工程,每个业务组件可能都需要一个组开发,类似淘宝这样的app。但这只是针对业务组件来说的,业务基础组件和基础组件修改的频率不会很大,最好都是单工程上传至maven仓库来使用。本文的例子是为了方便所以把所有组件写到一起了,最好的方式就是把 fun_ 和 module_ 开头的组件都拆分成单工程独立开发,业务组件写到一个工程内。 做完组件之间的隔离后,暴露出来最明显的问题就是页面跳转和数据通信的问题。一般来说,页面跳转都是显示startActivity跳转,在组件化项目内就不适用了,隐式跳转可以用,但每个Activity都要写 intent-filter 就显得有点麻烦,所以最好的方式还是用路由框架。 实际上市面已经有比较成熟的路由框架专门就是为了组件化而生的,比如美团的WMRouter,阿里的ARouter等,本例使用 ARouter 框架,看下ARouter页面跳转的基本操作。 首先肯定是引入依赖,以 module_common 引入ARouter举例,build.gradle 应该添加: android { defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { api rootProject.ext.dependencies[“arouter”] kapt rootProject.ext.dependencies[“arouter-compiler”] }
kapt注解依赖没有办法传递,所以我们不可避免得需要在每个模块都声明这些配置,除了 class AppCommon: BaseApp{ override fun onCreate(application: Application) { MLog.d(TAG, “BaseApp AppCommon init”) initARouter(application) } private fun initARouter(application: Application) { if(BuildConfig.DEBUG) { ARouter.openLog() ARouter.openDebug() } ARouter.init(application) } } 接着我们在 module_common 模块内声明一个路由表用作统一管理路径。 // RouterPath.kt class RouterPath { companion object { const val APP_MAIN = “/app/MainActivity” const val HOME_FRAGMENT = “/home/HomeFragment” const val MSG_FRAGMENT = “/msg/MsgFragment” const val ME_FRAGMENT = “/me/MeFragment” const val MSG_PROVIDER = “/msg/MsgProviderImpl” } } 然后在MainActivity类文件上进行注解: @Route(path = RouterPath.APP_MAIN) class MainActivity : AppCompatActivity() { } 任意模块只需要调用 ARouter.getInstance().build(RouterPath.APP_MAIN) .withString(“key”, “value”) .withObject(“key1”, obj) .navigation() 然后在MainActivity使用依赖注入接受数据: class MainActivity : AppCompatActivity() { @Autowired @JvmField var key: String = “” } ARouter 基本能满足所有的跳转需求。 前面已经提到组件通信是通过”间接依赖“解耦的,也就是会出现第三个"组件"作为中间件。如果是按照顺序阅读本文的话,就会发现工程目录中有出现 export_ 前缀的模块,这个模块其实是暴露了组件对外的接口,比如首页模块biz_home对应的"下沉接口"模块就是 export_biz_home,外部想要访问 biz_home 的功能只需要依赖 export_biz_home。这种每一个组件对应一个"下沉接口"组件看起来有点冗余,但若是项目很大的时候,这种方式是比较清晰的。当然若项目较小,可以考虑把所有暴露的接口整合到一个”下沉接口“组件,也就是本文例子的 module_base,然后module_common依赖module_base,这样每个模块都能使用任意模块的向外暴露的功能了,如果觉得下沉接口过多或者你需要严格界定每个组件,那就不推荐用这种方式了。 我们现在假设都是在export_声明对外暴露接口,场景是:从首页模块发送数值给消息模块,我的模块可以从消息模块获取数值。接下来介绍两种通信的方式。 Arouter方案在 export_biz_msg 组件下声明 IMsgProvider,此接口必须实现 IProvider 接口: interface IMsgProvider: IProvider { fun onCountFromHome(count: Int = 1) } 然后在 biz_msg 组件里实现这个接口: @Route(path = RouterPath.MSG_PROVIDER) class MsgProviderImpl: IMsgProvider { override fun onCountFromHome(count: Int) { // 这里只是对数据进行分发,有监听计数的对象会收到 MsgCount.instance.addCount(count) } override fun init(context: Context?) { // 对象被初始化时调用 } } 在 biz_home 首页组件中发送计数: val provider = ARouter.getInstance().build(RouterPath.MSG_PROVIDER) .navigation() as IMsgProvider provider.onCountFromHome(count) 可以看到其实和页面跳转的方式基本雷同,包括获取 Fragment 实例的方式也是这种。ARouter把所有通信的方式都用一种api实现,让使用者上手非常容易。 手动注册方案手动注册的方法其实也挺方便而且不需要其他框架支持,只是多了一步。我们也是在 export_biz_msg 声明一个接口 interface IMsgService { fun getMsgCount(): Int } 同样也是在 biz_msg 实现这个接口: class MsgServiceImpl: IMsgService { override fun getMsgCount(): Int{ // 获取消息模块内count值 return MsgCount.instance.getCount() } } 这里增加了一步手动注册: class MsgApp: BaseApp { override fun onCreate(application: Application) { MLog.d(TAG, “BaseApp MsgApp init”) MsgServiceUtil.setMsgService(MsgServiceImpl()) } } object MsgServiceUtil { private lateinit var msgService: fun setMsgService(msgService: IMsgService) { this.msgService = msgService } fun getMsgCount(): Int{ return msgService.getMsgCount() } } 我们写一个工具类 MsgServiceUtil 用来注册 IMsgService 服务,同时在biz_msg组件初始化的时候调用 setMsgService 真正注册进去。 在biz_me组件内调用: MsgServiceUtil.getMsgCount() 这里涉及消息组件的初始化,这个初始化时机就是应用Application创建的时机,下一节就是介绍如何进行Application生命周期的分发。 关于 Fragment 的获取,实际上如果采用ARouter方式,那么Fragment获取和Activity跳转基本一致,只需要用@Route 注解到Fragment类上。如果不用ARouter,那么就和手动注册下沉接口的通信方式一摸一样。 当 app 壳工程启动Application初始化时要通知到其他组件初始化一些功能。这里提供一个简单的方式。 首先我们在 module_common 公共库内声明一个接口 BaseApp: interface BaseApp { fun onCreate(application: Application) } 然后每个组件都要创建一个 App 类实现此接口,比如biz_home组件: class HomeApp: BaseApp { override fun onCreate(application: Application) { // 初始化都放在这里 MLog.d(TAG, “BaseApp HomeApp init”) } } |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 7:15:20- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |