IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android MVP架构终极封装 -> 正文阅读

[移动开发]Android MVP架构终极封装

Android应用开发项目默认是MVC架构的,对于古老的Java桌面开发来说,已经是一大进步了。但随着项目的复杂度越来越高,Activity明显hold不住日益膨胀的逻辑代码。各种回调也让Activity的生命周期回收处于失控边缘,导致各种难以排查的内存泄漏。

于是,MVP应运而生,甚至后来衍生了更加激进的MVVM,以及其他AAC等形形色色的架构。

正所谓大道至简,返璞归真。首先解释一下,为什么我从事移动开发8年了,偏偏对MVP情有独钟,因为个人觉得MVP比MVVM更能把控复杂的项目,虽然Presenter会持有Activity的引用(引入androidx.lifecycle.ViewModel后已经完美解决内存泄漏的问题),但模块独立,且回调非常方便。

这里提到MVVM,虽然不用特殊处理就可以解决内存泄漏的问题,但回调需要借助LiveData,且在xml里写代码,让我想起了当年被JSP支配的恐惧,抛开逻辑是否清晰不说,遇到问题时调试起来可能会让人抓狂。

下面介绍一下我熬了多个夜晚、成为光头才封装好的这个MVP框架,无需考虑内存泄漏的问题,且使用非常方便,可以自行选择是否启用屏幕适配、高刷新率等(本框架在Kotlin项目中使用可以把简洁优雅体现得淋漓尽致,Kotlin也是方向,今后移动应用的项目肯定以Kotlin为主了)。

一、项目配置

1.在build.gradle(app)同目录新建mvp.gradle文件

mvp.gradle的内容为:

dependencies {
    // 使用 retrofit + rx + gson 实现网络请求与解析
    def retrofit_version = '2.9.0'
    // 使用 retrofit + rx + gson 实现网络请求与解析---->
    api "com.squareup.retrofit2:retrofit:$retrofit_version"
    // 衔接 retrofit 和 rxjava
    api 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
    // 衔接 retrofit 和 gson
    api 'com.squareup.retrofit2:converter-gson:2.8.1'

    // 此处一定要注意使用RxJava2的版本,和Retrofit配合
    api 'io.reactivex.rxjava2:rxjava:2.2.17'
    api 'io.reactivex.rxjava2:rxandroid:2.1.1'

    // GSON
    api 'com.google.code.gson:gson:2.8.6'

    // 打印网络请求日志框架
    api "com.squareup.okhttp3:logging-interceptor:3.6.0"

    // 通用设计
    api "androidx.activity:activity:1.2.0-beta01"
    // ViewBinding
    api 'androidx.databinding:viewbinding:4.2.0@aar'

    // kotlin
    api "androidx.lifecycle:lifecycle-extensions:2.2.0"
    api "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
    api "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
    api "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
    api "androidx.preference:preference-ktx:1.1.1"
}

2.在build.gradle(app)顶部添加:

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}
apply from: 'mvp.gradle'

3.build.gradle(app)的android节点增加:

// 开启ViewBinding
buildFeatures{
    viewBinding = true
}

4.在gradle.properties文件增加:

android.useAndroidX=true
android.enableJetifier=true

5.把mvp.aar放到app/libs文件夹下,并在build.gradle(app)添加依赖:

implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])

以上就是所有的集成步骤了,看起来似乎有5步,其实每一步都非常简单。下面介绍部分常用功能使用:

二、基本使用

布局activity_test.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/tv_test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</FrameLayout>

Activity:

class TestActivity: BaseActivity<ActivityTestBinding>() {
    override fun onBindingInflate() = ActivityTestBinding.inflate(layoutInflater)

    /**
     * 延迟加载一个Presenter
     */
    private val mPresenter: TestPresenter by lazy()

    override fun onInit() {
        // 开始执行耗时任务
        mPresenter.runTimeConsumeTask()
    }

    fun onTaskResult(result: String?) {
        // 展示结果
        binding.tvTest.text = result
    }
}

温馨提示:activity添加android:configChanges="locale|orientation|screenSize|keyboardHidden"可以避免很多生命周期造成的问题,注意要指定主题继承自Theme.AppCompat哦。

Presenter:

class TestPresenter: BasePresenter<TestActivity>() {
    /**
     * 运行耗时任务
     */
    fun runTimeConsumeTask() {
        launchTask(
            {
                // 5秒耗时任务
                delay(5_000L)
                // 返回结果
                "success"
            }, onSuccess = {
                // 这里已经是主线程,回调
                view?.onTaskResult(it)
            }
        )
    }
}

怎么样,够简洁吧,不用关心内存泄漏,一个Activity可以多开Presenter,且Presenter可以在多个模块流转,只要把BasePresenter的泛型换成继承于IView的接口即可。

三、网络请求

1.网络管理者

/**
 * 网络请求封装
 */
object ApiManager {
    /**
     * 默认的网络请求
     * BASE_URL需要以/结尾,如:https://www.baidu.com/
     */
    val default = RetrofitManager.getDefault().createApiService(BuildConfig.BASE_URL, ApiService::class.java)
}

2.网络接口

/**
 * 请求接口
 */
interface ApiService {
    /**
     * 获取验证码接口
     */
    @GET("prod-api/api/login/smsCode")
    suspend fun sendSmsCode(@Query("phone") phone: String): BaseResponse<Any>
}

3.BaseResponse

/**
 * 统一返回封装
 */
@Keep
class BaseResponse<T> : IResponse {
    /**
     * 返回状态代码
     */
    var code = NetConstants.SUCCESS

    /**
     * 消息
     */
    var msg: String? = null

    /**
     * 返回的实体数据
     */
    var data: T? = null
    
    /**
     * 校验返回信息,如果没有错误也没有过期就返回true,如果有错误则抛出异常即可
     * 防止有些不需要使用到结果的接口不断提交失败,及时发现隐藏的重大错误如登录过期等
     */
    override fun valid(): Boolean {
        return true
    }
}

4.在Presenter中使用

/**
 * 发送验证码
 */
fun sendSms(phone: String) {
    launchTask(
        {
            ApiManager.default.sendSmsCode(phone)
        }, onResult = { success, result, code, message ->
            if (success) {
                ToastUtils.showShort("发送成功")
                view?.onSmsSuccess()
            } else {
                ToastUtils.showShort("发送失败:$message")
            }
        }
    )
}

四、实用扩展

1.申请权限

requestPermissions(Manifest.permission.CAMERA) { grant, temp ->
    if (grant) {
        ToastTools.showShort("granted")
    } else {
        ToastTools.showShort("deny")
    }
}

2.启动Activity

openActivity<MainActivity>()

3.启用高刷新率

enableHighRefreshRate()

4.startActivityForResult

openActivityForResult(intent, object : ActivityResult(){
    override fun onResultOK(backIntent: Intent?) {
        super.onResultOK(backIntent)
        ...
    }
})

5.防止快速点击

binding.btnTest.setSingleClick {
	...
}

6.扩大点击范围

binding.ivClose.expandClick()

7.设置Activity动画左进右出

MvpManager.getInstance().activityAnimation(SlideAnimation())

8.网络请求信息

RetrofitManager.getDefault()
    .addInterceptors(ChuckInterceptor(this)) // 在通知栏显示网络请求(部分手机需要手动开启通知权限)
    .printLog(true) // 是否在Logcat打印网络请求

其他屏幕适配、dp和sp转px等等

五、例子下载

这里提供的是一些封装好的API使用例子,提供的Demo是有偿下载的,一者是对我劳动的肯定;二者作为程序员,如果有什么想法,鼓励自己去学习与实现,会比直接拷贝来得充实。
Demo下载链接

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-09 20:49:02  更:2022-02-09 20:49:11 
 
开发: 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 14:46:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码