乐趣区

关于android:引入Jetpack架构后你的App会发生哪些变化

前言

上篇文章我给大家分享了我对 Android 架构 的了解,从思维层面去讲述架构的演进过程。很多小伙伴读完后拍手叫好,示意还想听我讲一下对 Jetpack 架构 的认识,本着帮人帮到底的精力,明天我将再次动笔 尽量从实质上讲清楚 Jetpack 架构 存在的意义,以及解决的问题。

同时我也有一个基于 Jetpack MVVM 的残缺开源我的项目,曾经依照上篇文章提出的思维做了重构,目前托管在Github,心愿也能为你提供一些帮忙。github 地址

常识储备:须要对 Lifcycle、LiveData、ViewModel、DataBinding 有根本理解

目录

  • 1. 有了 Lifecycle,再也不必放心生命周期同步问题

    • 1.1 为什么要做生命周期绑定?
    • 1.2 Lifecycle 解决了哪些问题?
  • 2. LiveData 并不是只使用观察者模式

    • 2.1 观察者模式的长处有哪些?
    • 2.2 LiveData 基于观察者模式又做了哪些扩大?
    • 2.3 LiveData + Lifecycle 实现 1 + 1 > 2
  • 3. ViewModel 与 LiveData 真乃天作之合

    • 3.1 如何优雅的实现 Fragment 之间通信?
    • 3.2 由 ViewModel 负责 VM/Presenter 的益处有哪些?
  • 4. 解除你对 DataBinding 的误会

    • 4.1 应用 DataBinding 的益处有哪些?
    • 4.2 为什么很多人说 DataBinding 很难调试?
  • 5. Jetpack 和 MVVM 有什么关系?

    • 5.1 什么是 MVVM
    • 5.2 Jetpack 只是让 MVVM 更简略、更平安

1. 有了 Lifecycle,再也不必放心生命周期同步问题

1.1 为什么要做生命周期绑定?

对于 Activity/Fragment 其最重要的概念就是生命周期治理,咱们开发者须要在不同生命周期回调中做不同事件。比方 onCreate 做一些初始化操作,onResume做一些复原操作等等等等,以上这些操作都比拟繁多间接去写也没有多大问题。

但有一些组件须要强依赖于 Activity/Fragment 生命周期,惯例写法一旦忽略便会引发平安问题,比方上面这个案例:

现有一个视频播放界面,咱们须要做到当跳到另一个界面就暂停播放,返回后再持续播放,退出后重置播放, 惯例思路:

#class PlayerActivity
    onCreate(){player.init()
    }
    onResume(){player.resume()
    }
    onPause(){player.pause()
    }
    onDestroy(){player.release()
    }

读过我上篇文章的小伙伴可能一眼就能看进去这违反了 管制反转 ,人不是机器很容易写错或者忘写,特地是player.release() 如果忘写便会引发内存透露 此时咱们能够基于 管制反转思维 (将 player 生命周期控制权交给不会出错的框架) 进行革新:第一步:

interface ObserverLifecycle{onCreate()
    ...
    onDestroy()}

首先定义一个观察者接口, 蕴含 Activity/Fragment 次要生命周期办法

第二步:

class BaseActivity{val observers = mutableList<ObserverLifecycle>()
    onCreate(){
        observers.forEach{observer.onCreate()
        }
    }
    ...
    onDestroy(){
        observers.forEach{observer.onDestroy()
        }
    }
}

BaseActivity 中察看生命周期并逐个告诉到 observers 的观察者

第三步:

class VideoPlayer : ObserverLifecycle{onCreate(){init()
    }
    ...
    onDestroy(){release()
    }
}
class PlayerActivity : BaseActivity{observers.add(videoPlayer)
}

播放器实现 ObserverLifecycle 接口,并在每个机会调用相应办法。PlayerActivity只需将 videoPlayer 注册到 observers 即可实现生命周期同步。

其实不光 videoPlayer,任何须要依赖Activity 生命周期的组件 只需实现 ObserverLifecycle 接口最初注册到 Activityobservers即可实现生命周期自动化治理,进而能够躲避误操作带来的危险

1.2 Lifecycle 解决了哪些问题?

既然生命周期的同步如此重要,Google 必定不会熟视无睹,尽管自定义 ObserverLifecycle 能够解决这种问题,但并不是每个人都能想到。所以 Google 就制订了一个标准化的生命周期管理工具 Lifecycle,让开发者碰到生命周期问题自然而然的想到Lifecycle,就如同想在Android 手机上新建一个界面就会想到 Activity 一样。

同时 ActivityFragment外部均内置了 Lifecycle,应用非常简单,以 1.1 案例通过Lifecycle 革新后如下:

class VideoPlayer : LifecycleObserver {@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate(){init()
    }
    ..
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy(){release()
    }
}
class PlayerActivity : BaseActivity{lifecycle.addObserver(videoPlayer)
}

两步操作即可,不必咱们本人向观察者 (videoPlayer) 做生命周期散发解决。

2. LiveData 并不是只使用观察者模式

2.1 观察者模式的长处有哪些?

观察者是一种常见并且十分实用的一种行为型模式,具备扩展性强、耦合性低的个性。

本文 1.1 中 生命周期同步设计就是一个规范的观察者模式,ObserverLifecycle 可作为观察者,PlayerActivity作为被观察者, 当被观察者 (PlayerActivity) 生命周期产生扭转时会被动告诉到观察者(VideoPlayer)

同时观察者在不扭转代码构造的状况随便扩大, 比方 PlayerActivity 属于一个 MVP 架构,此时能够将 Presenter 实现 ObserverLifecycle 作为观察者 随后 注册到被观察者 (PlayerActivity) 中,这样 Presenter 也能够监测到 Activity 生命周期,并且代码构造没有任何扭转,合乎 开闭准则(对扩大开发 批改敞开)

2.2 LiveData 基于观察者模式又做了哪些扩大?

LiveData符合标准的观察者模式,所以它具备扩展性强、耦合性低的个性,同样它还是一个存储数据的容器,当容器数据扭转时会触发观察者,即数据驱动。

数据驱动是前端开发畛域十分重要的一个概念,说数据驱动之前咱们先思考一个问题,为什么要扭转数据?答案不言而喻,无非是想让数据使用者感知到而已,而 LiveData 能够优雅的实现这一流程,将 扭转、告诉 两步操作合并为一步 即省事也进步了安全性.

依据 LiveData 的个性决定它非常适合去做数据驱动 UI,上面举个例子简略形容下:

# 需要:扭转 textView 内容以及对应的数据,用 LiveData 实现形式如下
val liveData = MutableLiveData<String>()
liveData?.observe(this, Observer { value->
            textView.text = value
        })
// 这一步会扭转 liveData 值并且会触发 textView 从新渲染
liveData.value = "android"

看起来平平无奇甚至天经地义,但它的确解决了咱们前端开发的痛点,在此之前数据和 UI 都须要咱们开发者独自批改,当面对十几个 View 时很难做到不漏不忘。引入 liveData 后扭转数据会主动触发 UI 渲染,将两步操作合并为一步,大大降低出错的概率 对于 数据驱动 UI上篇文章我曾经做了详细描述,感兴趣的能够翻回去查看。

2.3 LiveData + Lifecycle 实现 1 + 1 > 2

LiveDataLifecycle 的加持下能够实现只在可见状态接管告诉,说的艰深一点 Activity 执行了 onStop() 后外部的 LiveData 就无奈收到告诉,这样设计有什么益处?举个例子:ActivityAActivityB 共享同一个LiveData,伪代码如下

class ActivityA{
    liveData?.observe(this, Observer { value->
            textView.text = value
        })
}
class ActivityB{
    liveData?.observe(this, Observer { value->
            textView.text = value
        })
}

ActivityA 启动 ActivityB 后屡次扭转 liveData 值,等回到 ActivityA 时 你必定不心愿 Observer 收到屡次告诉而引发 textView 屡次 重绘。

引入 Lifecycle 后这个问题便可迎刃而解,liveData绑定 Lifecycle(例子中的 this) 后,当回到 ActivityA 时只会取 liveData 最新的值而后做告诉,从而防止多余的操作引发的性能问题

3. ViewModel 与 LiveData 真乃天作之合

3.1 Jetpack ViewModel 并不等价于 MVVM ViewModel

常常有小伙伴将 Jetpack ViewModelMVVM ViewModel 等量齐观,其实这二者基本没有在同一个档次,MVVM ViewModelMVVM 架构中的一个角色,看不见摸不着只是一种思维。而 Jetpack ViewModel 是一个实实在在的框架用于做状态托管,有对应的作用域可追随 Activity/Fragment 生命周期,但这种个性恰好能够充当 MVVM ViewModel 的角色,分隔数据层和视图层并做数据托管。

所以论断是 Jetpack ViewModel 能够充当MVVM ViewModel 但二者并不等价

3.2 如何优雅的实现 Fragment 之间通信?

ViewModel官网定义是一个带作用域的状态托管框架,可通过指定作用域和 Activity/Fragment 共存亡,为了将其状态托管施展到极致,Google 甚至独自为 ViewModel 开了个后门,Activity横竖屏切换时不会销毁对应的ViewModel,为的就是横竖屏能共用同一个ViewModel,从而保证数据的一致性。

既然是状态托管框架那 ViewModel 的第一要务 就要时时刻刻保障最新状态散发到视图层,这让我不禁想到了 LiveData,数据的承载以及散发交给 Livedata,而ViewModel 专一于托管 LiveData 保障不失落,二者搭配几乎是天作之合。

有了 ViewModelLiveDataFragment之间能够更优雅的通信。比方我的开源我的项目中的音乐播放器(属于 单 Activity 多 Fragment架构),播放页和首页悬浮都蕴含音乐根本信息,如下图所示:

想要使两个 Fragment 中播放信息实时同步,最优雅的形式是将播放状态托管在 Activity 作用域下 ViewModelLiveData中,而后各自做状态监听,这样只有要有一方扭转就能立刻告诉到另一方,简略又平安,具体细节可至我的开源我的项目中查看。

3.3 由 ViewModel 负责 VM/Presenter 的益处有哪些?

传统 MVVMMVP遇到最多的的问题无非就是多线程下的内存泄露,ViewModel能够齐全躲避这个问题,外部的 viewModelScope 是一个协程的扩大函数,viewModelScope生命周期追随 ViewModel 对应的 Lifecycle(Activity/Fragment),当页面销毁时会一并完结viewModelScope 协程作用域,所以将耗时操作间接放在 viewModelScope 即刻

另外在界面销毁时会调用 ViewModelonClear办法,能够在该办法做一些开释资源的操作,进一步升高内存泄露的危险

4. 解除你对 DataBinding 的误会

4.1 应用 DataBinding 的作用有哪些?

DataBinding最大的长处跟惟一的作用就是 数据 UI 双向绑定 UI 和数据 批改任何一方另外一方都会主动同步, 这样的益处其实跟 LiveData 的相似,都是做数据跟 UI 同步操作,用来保证数据和 UI 一致性。其实写到这能够发现,不论是 LiveDataDataBinding 还是 DiffUtil 都是用来解决数据和 UI 一致性问题,可见 Google 对这方面有如许器重,所以咱们肯定要紧跟官网步调

小知识点:

DataBinding 包中的 ObservableField 作用跟 LiveData 基本一致,但 ObservableField 有一个去重的成果,

4.2 为什么很多人说 DataBinding 很难调试?

常常听一些小伙伴提 DataBinding 不好用,起因是要在 xml 中写业务逻辑不好调试,对于这个观点我是持否定态度的。并不是我批准 xml 中写业务逻辑这一观点,我感觉碰到问题就得去解决问题,如果解决问题的路上有阻碍就尽量扫清阻碍,而不是一味的回避。

{vm.isShow ? View.VISIBLE : View.GONE} 之类的业务逻辑不写在 xml 放在哪好呢?对于这个问题我在上篇文章 Data Mapper 章节中形容的很分明,拿到后端数据转换老本地模型 ( 此过程会编写所有数据相干逻辑),本地模型与设计图一一对应,岂但能够将视图与后段隔离,而且能够解决 xml 中编写业务逻辑的问题。

5. Jetpack 和 MVVM 有什么关系?

5.1 什么是 MVVM

MVVM其实是前端畛域一个专一于界面开发的架构模式,总共分为 ViewViewModelRepository 三个模块 (需严格依照繁多设计准则划分)

  • View(视图层): 专门做视图渲染以及 UI 逻辑的解决
  • Repository(近程): 代表近程仓库,从 Repository 取须要的数据
  • ViewModel: Repository 取出的数据需暂存到 ViewModel,同时将数据映射到视图层

分层诚然重要,但 MVVM 最外围点是通过 ViewModel 做数据驱动 UI 以及双向绑定的操作用来解决 数据 /UI的一致性问题。MVVM就这么些货色,千万不要把它了解的特地简单

双向绑定和单向驱动应该如何抉择?

当面临 TextView 之类的 View单向驱动 曾经齐全够用了,毕竟在咱们的认知里是不须要通过 TextView 显示的 文案 扭转对应数据的,此时单向驱动就能保障 数据、UI统一。而双向绑定通常用在可交互式的 View 中,比方 EditText 内容会通过用户输出而扭转的,此时须要通过双向绑定能力保障 数据、UI统一。不论是 双向绑定 还是 单向驱动 ,只有能保障 数据、UI统一,那它就合乎 MVVM 思维

其实我上篇文章也简略说过,好的架构不应该局限到某一种模式 (MVC/MVP/MVVM) 上,须要依据本人我的项目的理论状况一直添砖加瓦。如果你们的后端比拟善变我倡议引入 Data Mapper 的概念~如果你常常和共事开发同一个界面,能够试图将每一条业务逻辑封装到 use case 中,这样大概率能够解决 Git 抵触 的问题.. 等等等等,总之只有能实实在在 进步 开发效率以及我的项目稳定性的架构就是好架构.

5.2 Jetpack 只是让 MVVM 更简略、更平安

Jetpack是 Android 官网为确立标准化开发而提供的一套框架,Lifecycle能够让开发者不必过多思考 生命周期引发的一系列问题 ~ 有了 DataBinding 的反对让数据 UI 双向绑定成为了可能 ~ LiveData的存在解除 ViewModelActivity双向依赖的问题 ….

归根到底 Jetpack 就是一套开发框架,MVVM在这套框架的加持之下变得更加简略、平安。

Tips: 作者公司我的项目引入 Jetpack 后,我的项目稳定性有着肉眼可见的晋升。

综上所述

  • Lifecycle 解决了生命周期 同步问题
  • LiveData 实现了真正的状态驱动
  • ViewModel 能够让 Fragment 通信变得更优雅
  • DataBinding 让双向绑定成为了可能
  • Jetpack 只是让 MVVM 更简略、更平安

相干视频举荐:

【2021 最新版】Android studio 装置教程 +Android(安卓)零基础教程视频(适宜 Android 0 根底,Android 初学入门)含音视频_哔哩哔哩_bilibili

Android 架构设计原理与实战——Jetpack 联合 MVP 组合利用开发一个优良的 APP!_哔哩哔哩_bilibili

Android 进阶必学:jetpack 架构组件—Navigation_哔哩哔哩_bilibili

Android 进阶零碎学习——Jetpack 先天优良的基因能够防止数据内存透露_哔哩哔哩_bilibili

本文转自 https://juejin.cn/post/6955491901265051661,如有侵权,请分割删除。

退出移动版