Android应用-开发框架设计

目录

1. 📂 简介

1.1 背景

1.2 专业术语

2. 🔱 总体设计思想

2.1 分层:组件化设计框架

2.2 分类:应用开发架构图

3. ⚛️ 框架详细设计

3.1 组件化框架外形

3.2 业务模块化

3.3 代码编程框架

4. 💠 框架其他设计

4.1 版本统一控制

4.2 引入部分第三方框架

4.3 封装网络请求框架

4.4 统一应用签名


1. 📂 简介

1.1 背景

        为减少应用开发重复造轮子,于是希望有一套统一的应用框架,可以让应用开发者快速上手开发需求,而无需过多关注应用框架相关内容。

        而且,基于同一套应用框架,有利于同事互相之间的代码Review与维护,也方便后期项目交接。不仅减少开发人员繁复的工作,而且提升整个团队的产研效率。

1.2 专业术语

术语名称

描述

AndroidStudio

简称AS,是Android开发者用来开发应用的一个工具

Retrofit/okhttp3

知名的网络请求框架

Glide

知名的图片加载框架

LiveEventBus

基于LiveData的应用开发事件总线,方便业务间消息通信,有取代EventBus的趋势

MVVM

基于MVC、MVP的一套代码开发框架

Kotlin

Android开发官方推荐语言

2. 🔱 总体设计思想

2.1 分层:组件化设计框架

        我们知道常见的应用开发框架主要有:模块化、组件化、插件化,那么随着各个应用不断的迭代升级,应用的开发框架也从最开始的单App模块到多模块化,再到组件化与插件化。那么对于一般的应用开发框架,应该遵循什么样的设计原则呢?

        首先,我想到的是不能过度设计,一口不能吃一个大胖子,一来就嚷着要做插件化是不太现实的,框架应该跟随应用需求一步步迭代或重构。其次,直接使用AS创建一个新项目,会缺少应用迭代升级的一些常见元素(如常见的Retrofit、Glide、LiveEventBus等三方开源SDK和一些工具类),在后期慢慢引入时很可能会没有必要的重复踩前人走过的坑。于是,依赖于组件化设计思想——无惧应用后期扩展迭代,再结合应用基本所需元素——搭一个轮子减少重复劳动,就设计出本文将要阐述的应用开发框架,具体思想请继续往下看。

2.2 分类:应用开发架构图

        总体方向是:首先建立一个组件化框架的外形架构,然后实现业务模块化,再搭建一套MVVM+Kotlin代码编程框架。

3. ⚛️ 框架详细设计

3.1 组件化框架外形

        以app模块为总入口,作为组件化中提到的壳工程。app模块不应包含相关业务代码,它的主要工作应该是进行Application初始化、依赖各个模块,和声明各模块manifest相关配置。

3.2 业务模块化

        app模块依赖portal业务模块,暂且我们可将所有业务写在portal模块,后期业务壮大后可朝组件化方向再拆分业务模块。

        middleware模块作为中间件层,放置一些模块间共用的元素,那么项目中除middleware模块之外的其他所有模块,如:app模块和portal模块,都应依赖middleware模块。但需注意,随着业务的增长middleware模块可预料的会不断膨胀,所以写业务时需注意解耦,切勿将非模块间公用的元素放进middleware模块。

        portal模块包括主要的业务代码,采用组件化分包方式搭建各业务模块,比如下面这样的包名结构:

  • com.xxx.xxx.portal.feature.home

  • com.xxx.xxx.portal.feature.bt

  • com.xxx.xxx.portal.feature.wifi

3.3 代码编程框架

        各业务模块采用MVVM框架,包结构为:data-model-view-viewmodel

        使用Kotlin语言,依赖于下沉到middleware模块的BaseActivity、BaseFragment,以及ViewBinding,建立起一套如下的代码编程框架:

4. 💠 框架其他设计

4.1 版本统一控制

        根目录新建version.gradle文件,将各类版本号统一放置此处,在其他gradlle脚本通过 apply from: "${rootDir}/version.gradle" 导入使用。

4.2 引入部分第三方框架

        在middleware模块中引入一些应用开发必要的第三方库,主要包括blankj工具包合集、图片加载框架Glide、网络请求框架和相关配置Retrofit/okhttp3、动效加载工具lottie、以及应用开发事件总线LiveEventBus等。

    api "androidx.constraintlayout:constraintlayout:$CONSTRAINTLAYOUT"
    api "androidx.lifecycle:lifecycle-livedata-ktx:$LIVEDATA"
    api "androidx.lifecycle:lifecycle-viewmodel-ktx:$VIEWMODEL"
    api "androidx.viewpager2:viewpager2:$VIEWPAGER2"
    api "com.blankj:utilcodex:$COM_BLANKJ_UTILCODEX"
    api "com.github.bumptech.glide:glide:$GLIDE"
    api "com.squareup.retrofit2:retrofit:$RETROFIT"
    api "com.squareup.retrofit2:converter-gson:$RETROFIT_CONVERTER_GSON"
    api "com.squareup.retrofit2:adapter-rxjava:$RETROFIT_ADAPTER_RXJAVA"
    api "com.squareup.okhttp3:logging-interceptor:$OKHTTP_LOGGING_INTERCEPTOR"
    api "com.airbnb.android:lottie:$LOTTIE"
    api "io.github.jeremyliao:live-event-bus-x:$LIVE_EVENT_BUS_X"

4.3 封装网络请求框架

        基于Retrofit/okhttp3,封装出相应的ApiFactory以及BaseModel、BaseViewModel,方便基于MVVM项目访问网络,本应用开发框架中已包含整套网络请请求和处理的编程范式,具体可参考如下代码:

Model层:

interface MainApi {

    // 随机获取1张猫图(GET):https://api.thecatapi.com/v1/images/search?limit=1
    @GET("v1/images/search")
    suspend fun getCat(@QueryMap hashMap: HashMap<String, String>): List<CatBean>
//    suspend fun getCat(@QueryMap hashMap: HashMap<String, String>): BaseResponse<CatBean>

}

class MainModel : BaseModel<MainApi>() {

    override fun createApi(): Class<MainApi> = MainApi::class.java

    //    suspend fun getCat(hashMap: HashMap<String, String>): BaseResponse<CatBean> =
    suspend fun getCat(hashMap: HashMap<String, String>): List<CatBean> =
        withContext(Dispatchers.IO) {
            try {
                apiStores.getCat(hashMap)
            } catch (e: Exception) {
                mutableListOf()
            }
        }
}

abstract class BaseModel<T> {

    protected var apiStores: T

    init {
        apiStores = ApiFactory.remoteService(createApi())
    }

    protected abstract fun createApi(): Class<T>

}

网络请求工厂:

object ApiFactory {

    private val okHttpClient: OkHttpClient by lazy { setHttpClient() }

    private fun retrofit(): Retrofit {
        return Retrofit.Builder().baseUrl(Constants.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()).client(okHttpClient).build()
    }

    private fun setHttpClient(): OkHttpClient = OkHttpClient.Builder().apply {
        addInterceptor(InterceptorManager.headerInterceptor()).addInterceptor(InterceptorManager.httpLoggingInterceptor())
        InterceptorManager.otherInterceptors.forEach { addInterceptor(it) }
    }.connectTimeout(NET_TIMEOUT, TimeUnit.SECONDS).readTimeout(NET_TIMEOUT, TimeUnit.SECONDS)
        .writeTimeout(NET_TIMEOUT, TimeUnit.SECONDS).build()

    @JvmStatic
    fun <T> remoteService(apiService: Class<T>): T {
        return retrofit().create(apiService)
    }

}

 网络请求拦截器:

object InterceptorManager {

    /**
     * 返回头拦截器
     * @return
     */
    fun headerInterceptor(): Interceptor = Interceptor { chain: Interceptor.Chain ->
        chain.proceed(
            chain.request().newBuilder().addHeader(HeaderNames.TOKEN.headerName, "")
                .addHeader(HeaderNames.PLATFORM.headerName, "android")
                .addHeader(HeaderNames.UID.headerName, "")
                .addHeader(HeaderNames.VERSION.headerName, AppUtils.getAppVersionName()).build()
        )
    }

    /**
     * 返回http拦截器
     */
    fun httpLoggingInterceptor(): Interceptor = HttpLoggingInterceptor().apply {
        this.level =
            if (Constants.RELEASE) HttpLoggingInterceptor.Level.NONE else HttpLoggingInterceptor.Level.BODY
    }

    /**
     * 自定义http拦截器
     */
    var otherInterceptors: MutableList<Interceptor> = mutableListOf()

    enum class HeaderNames(val headerName: String) {
        TOKEN("Token"), PLATFORM("Platform"), UID("UID"), VERSION("Version"),
    }

}

4.4 统一应用签名

        在app模块中新增signing.properties文件存储签名信息,xxx.jks签名文件放在同级目录,然后在app模块build.dradle文件中增加如下签名校验信息:

Properties signingProps = new Properties()
signingProps.load(new FileInputStream(file("signing.properties")))

android {
    signingConfigs {
        KeyStore {
            keyAlias signingProps['KEY_STORE_ALIAS']
            keyPassword signingProps['KEY_STORE_KEY_PASSWD']
            storeFile file(signingProps['KEY_STORE_FILE'])
            storePassword signingProps['KEY_STORE_PASSWD']
            v1SigningEnabled true
            v2SigningEnabled true
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            signingConfig signingConfigs.KeyStore
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

        debug {
            minifyEnabled false
            signingConfig signingConfigs.KeyStore
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/21021.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

本地git仓库(gitea)与openssh-server的冲突(connection reset by ip port 22)

前提 之前在本地的windows电脑上安装了一个gitea供项目组成员使用。 期间为了在windows电脑上使用scp拷贝文件&#xff0c;离线安装过一个openssh。 冲突 发现无法pull/clone gitea上的仓库了&#xff0c;提示 connection reset by ip port 22 fatal: Could not read from r…

【ChatGPT】无需注册,无需科学上网,无需人工验证的速度超快的 ChatGPT

文章目录 一、ChatGPT介绍二、使用ChatGPT时经常遇到的一些问题三、一个让你呼吸顺畅的 ChatGPT 一、ChatGPT介绍 ChatGPT&#xff0c;全称聊天生成预训练转换器&#xff08;英语&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;是OpenAI开发的人…

BGP路由选择实验

测试环境拓扑图 每一种规则测试完后记得恢复初始状态&#xff01;&#xff01; 各设备BGP Router_ID为loopback 0的地址。 AR1 配置 [V200R003C00] #sysname AR1 # interface GigabitEthernet0/0/0ip address 10.1.12.1 255.255.255.0 # interface LoopBack0ip address 1.1.…

vue大屏开发系列—使用echart开发省市地图数据,并点击省获取市地图数据

1. 本文在基础上进行改进&#xff0c;后端使用若依后端 IofTV-Screen: &#x1f525;一个基于 vue、datav、Echart 框架的物联网可视化&#xff08;大屏展示&#xff09;模板&#xff0c;提供数据动态刷新渲染、屏幕适应、数据滚动配置&#xff0c;内部图表自由替换、Mixins注入…

揭 秘~月薪2-3万的程序员一天到底是怎么度过的?

程序员的高薪资&#xff0c;一直是大家热衷讨论的话题&#xff0c;几乎每隔一段时间就会在社交平台被网友们热议一番。 比如这条“月薪2万到3万的程序员的一天是怎么样度过的&#xff1f;”的帖子就一直排在知乎前列。 作为薪资可观的岗位&#xff0c;大家都非常好奇&#xff…

22届硕士,去年秋招拿了字节跳动offer,有一说一,不是很难进

自从抖音短视频APP火了之后&#xff0c;起公司字节跳动也逐渐向着大厂靠拢&#xff0c;相信大家都已经对这家公司很熟悉了&#xff0c;尤其是近几年来&#xff0c;对它的认识也在不断刷新&#xff0c;它惊人的发展速度确实让行业内人刮目相看&#xff0c;如今很多年轻人也想要挤…

ChatGPT的工作原理(纯干货,万字长文)

ChatGPT 能够自动生成一些读起来表面上甚至像人写的文字的东西&#xff0c;这非常了不起&#xff0c;而且出乎意料。但它是如何做到的&#xff1f;为什么它能发挥作用&#xff1f;我在这里的目的是大致介绍一下 ChatGPT 内部的情况&#xff0c;然后探讨一下为什么它能很好地生成…

Rust每日一练(leetDay0001) 两数之和、两数相加、最长子串

目录 1. 两数之和 Two Sum &#x1f31f; 2. 两数相加 Add Two Numbers &#x1f31f;&#x1f31f; 3. 无重复字符的最长子串 Longest substring without repeating characters &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练…

内网渗透(七十八)之域权限维持之ACL滥用(下)

ACL滥用(下) 7、GenericAll 权限 应用于组 再来看看GenericAll 权限 应用于组如何进行权限维持。 由于用户hack是普通的域用户,因此他没有往Domain Admins 组添加用户的权限,如图所示,以用户hack 身份往Domain Admins 组中添加用户,可以看到,添加用户失败。 现在我们…

孙鑫VC++第四章 2.简单绘图-绘制

目录 1. 按键消息 2. 绘制线条 2.1 利用SDK全局函数实现画线功能 2.2 利用MFC的CDC类实现画线功能 2.3 利用MFC的CClientDC类实现画线功能 2.4 利用MFC的CWindowDC类实现画线功能 3. 在桌面窗口中画线 3.1 绘制彩色线条 4. 使用画刷绘图 4.1 简单画刷 4.2 位图画刷 …

『手撕 Mybatis 源码』02 - 加载配置文件

加载配置文件 获取输入流 myBatis 的配置文档层次架构 首先从读入开始查看是怎么加载配置文件的&#xff0c;现在从这里打个断点 public class MybatisTest {Testpublic void test1() throws IOException {// 1. 通过类加载器对配置文件进行加载&#xff0c;加载成了字节输入…

代码随想录算法训练营第二十三天|理论基础 77. 组合

文章目录 理论基础77.组合思路代码总结 理论基础 回溯算法&#xff1a;一种暴力搜索方式 回溯是递归的副产品&#xff0c;只要有递归就会有回溯。 回溯法&#xff0c;一般可以解决如下几种问题&#xff1a; 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合切割问题…

学术加油站|基于LSM-tree存储系统的内存管理,最大限度降低I/O成本

本文系北京理工大学科研助理牛颂登所著&#xff0c;本篇也是 OceanBase 学术系列稿件第 10 篇。欢迎访问 OceanBase 官网获取更多信息&#xff1a;https://www.oceanbase.com/ 「牛颂登&#xff1a;北京理工大学科研助理&#xff0c;硕士期间在电子科技大学网络空间安全研究院从…

antd-vue-admin——通过链接跳过登录页直接进入系统内部——基础积累

最近在写后台管理系统&#xff0c;遇到一个需求&#xff0c;就是从系统A带参数可以直接进入到系统B内部。不通过系统B的登录页面进行登录。 一般系统的登录&#xff0c;都需要用户名和密码等参数&#xff0c;然后获取到token信息&#xff0c;最后进入到系统内部。 下面介绍具…

4. QT中的鼠标键盘事件 --- 鼠标拖拽案例

1. 说明 在QT的控件或者窗口当中&#xff0c;如果对于当前鼠标或者键盘的功能需要自己定义&#xff0c;可以重写父类当中对应虚函数&#xff0c;主要包括以下几个&#xff1a; //键盘按键按下 virtual void keyPressEvent(QKeyEvent *event); //键盘按键抬起 virtual void ke…

linux 常用命令awk

AWK 是一种处理文本文件的语言&#xff0c;是一个强大的文本分析工具。之所以叫 AWK 是因为其取了三位创始人 Alfred Aho&#xff0c;Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。 AWK用法 awk 用法&#xff1a;awk pattern {action} files 1.RS, ORS, F…

【c语言】组件化打包—静态库lib

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c语言系列专栏&#xff1a;c语言之路重点知识整合 &#x…

CVE-2023-32233 Linux kernel

0x01 漏洞介绍 近日&#xff0c;研究人员发现了Linux内核的NetFilter框架中的新漏洞&#xff08;CVE-2023-32233&#xff09;。该漏洞可被本地用户用于将权限提升为root&#xff0c;并完全控制系统。问题的根源在于tfilter nf_tables是如何处理批处理请求的&#xff0c;经过身…

AutoSizer.exe:自动调整窗口大小的便捷工具

AutoSizer.exe是一款实用的桌面应用程序,它旨在帮助用户自动调整窗口大小,提供更好的用户体验。无论您是在使用Windows操作系统进行日常工作还是进行多任务处理,AutoSizer.exe可以简化您的工作流程,提高效率。本文将介绍AutoSizer.exe的下载地址、功能介绍、使用方法以及其…

为世界第一大癌症高效研发首创新药,AI大模型助力药物研发叩开未来之门

近日&#xff0c;三位高中生引爆了医药圈&#xff0c;他们使用人工智能&#xff08;AI&#xff09;引擎进行靶点发现&#xff0c;确定了多形性胶质母细胞瘤&#xff08;GBM&#xff09;的新治疗靶点&#xff0c;多形性胶质母细胞瘤&#xff08;GBM&#xff09;是最具侵袭性和最…
最新文章