Android 架构组件——kotlin相关基础知识点(进阶必备)_override fun oncreate(savedinstancestate: bundle?)-程序员宅基地

技术标签: Android开发  架构  android  kotlin  Android  

本文为译文,原文链接:
https://medium.com/@elye.project/android-architecture-components-for-dummies-in-kotlin-50-lines-of-code-29b29d3a381

以前写 android 程序时,只需要把所有代码写在 Activity 中就可以了,比如:

class MainActivity : AppCompatActivity() {
    private var count = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        my_container.setOnClickListener { incrementCount() }
    }

    override fun onResume() {
        super.onResume()
        incrementCount()
    }

    private fun incrementCount() {
        my_text.text = (++count).toString()
    }
}

仅仅用小于 20 行的代码,你就可以实现一个计数程序,统计每次你点击和前台显示 App 的次数。

这样的代码虽然简单,但是却难以扩展成一个大型项目,就像上图中的小房子一样,有很多问题:

  1. 如果你旋转你的设备,count 会被重置为 0
  2. 这样的代码很难进行单元测试
  3. 把所有东西都放在一个 class 里面,会让开发者变笨变迟钝。也许你是个菜鸟,但你一定不想变成笨笨的开发者。

代码架构

有许多中方法可以更好地组织你的代码结构。最基本的方法就是把代码拆分成不同的 class ,我们称其为 关注点分离
你可能听说过 MVP 、MVC 、MVVM…如果你很了解这些概念并且运用自如,那么你可以不用看这篇文章了,去喝杯咖啡然后干别的事情吧

如果不是的话,那么请继续读下去…

简单来说,通过把逻辑代码尽可能多地从 Activity 当中移到别的类当中就可以实现关注点分离。你地 Activity 只会去处理和 Android 本身相关地工作,以及 UI 的更新。让别的类来处理重要的逻辑事务。

这样的话。任何 LifeCycle 事件都由 Activity 通知 Logic class ,同时对于任何数据的改变,你的 Logic class 都会将其通知到 Activity 。
很简单吧?虽然听起来很简单,但是每个人具体实现的方式都不同。这就是 MVP 、MVC 、MVVM (我甚至听过 MVVMI)的由来。即使是同一种架构,代码写法也会有许多不同。

谷歌看不下去了

开发者使用各种架构、各种方法来分离视图和逻辑层,那么哪种是最好的呢?人们忍不住问谷歌。于是在 2017 的 Google IO 大会上,Google 决定提出他自己的解决方案。这就是我们说的 Android Architecture Components (安卓架构组件)。
如下图所示,看起来和前文的图几乎一样,但是有了更清楚的命名。

什么是 MVVM(Model View ViewModel)?

当你看见 ViewModel 这个词的时候,你可能会很容易的就联想到 MVVM 。但是 MVVM 到底是什么?
简单来说,它是基于 观察者 模式实现的架构。
在这种模式中,信息的提供者并不知道谁需要他去提供这些信息。但是对这些信息感兴趣的人会对其进行订阅,一旦信息发布,就可以获取到需要的信息。

就像你订阅一个 B 站 UP 主一样,他们一更新,你就能得到通知

这样,你大概就能猜到:

  1. ViewModel 通过 Activity 的 LifeCycle 对象订阅 Activity ,以便在 LifeCycleEvents 发生时得到通知
  2. Activity 通过ViewModel 的 LiveData 对象订阅 ViewModel ,以便在数据更新时得到通知

使用安卓架构组件

好了,理论已经谈得足够多了,现在让我们来看看怎么在代码中使用他们。

添加依赖

在我给出的这个例子中,在 app 的 build.gradle 中添加下面的依赖就足够了。还有很多其他的库,但是现在不需要它们。

implementation "android.arch.lifecycle:extensions:1.1.0"

ViewModel 类和它的 LiveData

依赖添加完之后,就创建一个 ViewModel 类

class MyViewModel(private var count: Int = 0) : ViewModel() {
        val changeNotifier = MutableLiveData<Int>()
        fun increment() { changeNotifier.value = ++ count }
}

为了能够更简单地在 Activity 中使用它,最好是继承自 ViewModel 。现在这个类中包含了count变量,在我们点击或者 activity 出现在前台时,我们会用它进行 UI 的更新。除此之外,还包含了 名为 changeNotifier的 MutableLiveData 。只要count发生改变,我仅需要相应地更新 changeNotifier.value ,不论是谁订阅了它,都能获取更新的数据。

在 MainActivity 中使用 ViewModel

完成了上述工作,现在我们需要把这个 ViewModel 类提供给我们的 MainActivity。

class MainActivity : AppCompatActivity() {
    private val viewModel: MyViewModel by lazy {
        ViewModelProviders.of(this).get(MyViewModel::class.java)
    }

    private val changeObserver =
            Observer<Int> { 
                 value -> value?.let { incrementCount(value) } 
            }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel.changeNotifier.observe(this, changeObserver)
        my_container.setOnClickListener { viewModel.increment() }
    }

    private fun incrementCount(value: Int) {
        my_text.text = (value).toString()
    }
}

我们使用了lazy关键词来创建viewModel,这是谷歌推荐的方法

private val viewModel: MyViewModel by lazy {
        ViewModelProviders.of(this).get(MyViewModel::class.java)
    }

之后, 我们的代码写出了获取消息的行为以及获得消息后干什么。在 Kotlin 中,我们使用 lambda 表达式,这样会让代码看起来更干净。

private val changeObserver =
            Observer<Int> { 
                 value -> value?.let { incrementCount(value) } 
            }

之后我们必须使用下面的代码将 changeObserver注册到viewModel

viewModel.changeNotifier.observe(this, changeObserver)

最后, 我们需要一个方法从 UI 去触发数据的变化。在这个例子中是通过点击事件。

my_container.setOnClickListener { viewModel.increment() }

从 MainActivity 到 ViewModel 再回到 MainActivity 就像是一趟往返的路途。我们并没有把所有的事情都放到 MainActivity 中来做,这样虽然看起来复杂了一点,但是我们却搭建了一个好的 App 架构。这样就能把逻辑代码全部转移到 ViewModel 中而不是 MainActivity 。

让 ViewModel 感知到 Activity 的生命周期变化

为了让 ViewModel 感知到 Activity 的生命周期变化,我们需要让它实现 LifeCycleObserver接口。

class MyViewModel(private var count: Int = 0) : ViewModel(),   
    LifecycleObserver {
    val changeNotifier = MutableLiveData<Int>()
    fun increment() { changeNotifier.value = ++count }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) 
    fun onResume() { increment() }
}

你的 viewModel依赖于哪一个生命周期,就添加一个 @OnLifecycleEvent 注解。
在这个例子中,我们只对 ON_RESUME 感兴趣。
做完这步后,我们需要让viewModel订阅 MainActivityLifecycle事件。在最新版本的 AppCompatActivity 类中,LifeCycle已经添加进来了。所以我们可以轻松地在onCreate函数中实现如下代码:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel.changeNotifier.observe(this, changeObserver)
        lifecycle.addObserver(viewModel)             
        my_container.setOnClickListener { viewModel.increment() }
    }

现在viewModel就不需要让MainActivity在每个生命周期事件发生时主动地调用viewModel的方法。只需要合适的@OnLifeCycleEvent注解,viewModel就会被通知到并且执行相应的逻辑。

妈妈再也不用担心我旋转设备了

现在我们可以轻松地扩展我们地 App ,在viewModel中实现更复杂地逻辑。并且,相比于Activity,我们在可以在viewModel中更好地进行单元测试。
除此之外,最重要地一点时,当我们旋转设备时,count不会再被重置为 0 。它的值被保存下来了,因为 Android 内部实现了在 ViewModel 中保存数据的机制,不需要你去显式地保存它。

但也不要高兴地太早

虽然 ViewModel 可以很好地保存数据,但是这并不意味着onSaveInstanceState就没有用武之地了。如果 Activity 被进程被系统杀死,那么count地值就不会被保存。
为了处理这个问题,我添加了处理savedInstanceState的逻辑代码。

class MainActivity : AppCompatActivity() {
    private val viewModel: MyViewModel by lazy {
        ViewModelProviders.of(this).get(MyViewModel::class.java)
    }

    private val changeObserver = Observer<Int> { 
                  value -> value?.let { incrementCount(value) } 
            }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel.restoreState(savedInstanceState)
        viewModel.changeNotifier.observe(this, changeObserver)
        lifecycle.addObserver(viewModel)
        my_container.setOnClickListener { viewModel.increment() }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        viewModel.saveState(outState)
    }

    private fun incrementCount(value: Int) {
        my_text.text = (value).toString()
    }
}

class MyViewModel(private var count: Int = 0) : ViewModel(), 
    LifecycleObserver {
    companion object { const val COUNT_KEY = "CountKey" }

    val changeNotifier = MutableLiveData<Int>()

    fun increment() { changeNotifier.value = ++count }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) 
    fun onResume() { increment() }

    fun saveState(outState: Bundle) {
        outState.putInt(COUNT_KEY, count)
    }

    fun restoreState(inState: Bundle?) {
        inState?.let { count = inState.getInt(COUNT_KEY) }
    }
}

这样,不论是旋转设备还是进程被杀死,你的count值都可以被保留下来。

源码可以从以下链接获得:
https://github.com/elye/demo_android_architecture_components?source=post_page-----29b29d3a381

关于 ViewModel ,再说一点

可能上面最终的代码看起来比一开始直接在 Activity 中处理所有事情的代码要长很多。但是,如同画房屋设计图一样,想要实现更多细节,就必须有合理的组织架构,即把逻辑代码从 Activity 当中抽离出来。
我的观点是,如果你已经有熟悉的架构,并且运用自如,那么你就可以不用安卓架构组件, Android Architecture Componens 。除非它能为代码提供更好的表现,比如在杀死和恢复应用进程时保留变量值。

文末福利

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

一、架构师筑基必备技能

1、深入理解Java泛型
2、注解深入浅出
3、并发编程
4、数据传输与序列化
5、Java虚拟机原理
6、高效IO
……

在这里插入图片描述

二、Android百大框架源码解析

1.Retrofit 2.0源码解析
2.Okhttp3源码解析
3.ButterKnife源码解析
4.MPAndroidChart 源码解析
5.Glide源码解析
6.Leakcanary 源码解析
7.Universal-lmage-Loader源码解析
8.EventBus 3.0源码解析
9.zxing源码分析
10.Picasso源码解析
11.LottieAndroid使用详解及源码解析
12.Fresco 源码分析——图片加载流程

在这里插入图片描述

三、Android性能优化实战解析

  • 腾讯Bugly:对字符串匹配算法的一点理解
  • 爱奇艺:安卓APP崩溃捕获方案——xCrash
  • 字节跳动:深入理解Gradle框架之一:Plugin, Extension, buildSrc
  • 百度APP技术:Android H5首屏优化实践
  • 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
  • 携程:从智行 Android 项目看组件化架构实践
  • 网易新闻构建优化:如何让你的构建速度“势如闪电”?

在这里插入图片描述

四、高级kotlin强化实战

1、Kotlin入门教程
2、Kotlin 实战避坑指南
3、项目实战《Kotlin Jetpack 实战》

  • 从一个膜拜大神的 Demo 开始

  • Kotlin 写 Gradle 脚本是一种什么体验?

  • Kotlin 编程的三重境界

  • Kotlin 高阶函数

  • Kotlin 泛型

  • Kotlin 扩展

  • Kotlin 委托

  • 协程“不为人知”的调试技巧

  • 图解协程:suspend

在这里插入图片描述

五、Android高级UI开源框架进阶解密

1.SmartRefreshLayout的使用
2.Android之PullToRefresh控件源码解析
3.Android-PullToRefresh下拉刷新库基本用法
4.LoadSir-高效易用的加载反馈页管理框架
5.Android通用LoadingView加载框架详解
6.MPAndroidChart实现LineChart(折线图)
7.hellocharts-android使用指南
8.SmartTable使用指南
9.开源项目android-uitableview介绍
10.ExcelPanel 使用指南
11.Android开源项目SlidingMenu深切解析
12.MaterialDrawer使用指南
在这里插入图片描述

六、NDK模块开发

1、NDK 模块开发
2、JNI 模块
3、Native 开发工具
4、Linux 编程
5、底层图片处理
6、音视频开发
7、机器学习

在这里插入图片描述

七、Flutter技术进阶

1、Flutter跨平台开发概述
2、Windows中Flutter开发环境搭建
3、编写你的第一个Flutter APP
4、Flutter开发环境搭建和调试
5、Dart语法篇之基础语法(一)
6、Dart语法篇之集合的使用与源码解析(二)
7、Dart语法篇之集合操作符函数与源码分析(三)

在这里插入图片描述

八、微信小程序开发

1、小程序概述及入门
2、小程序UI开发
3、API操作
4、购物商场项目实战……

在这里插入图片描述

全套视频资料:

一、面试合集
在这里插入图片描述
二、源码解析合集

在这里插入图片描述
三、开源框架合集

在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

请添加图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/YoungOne2333/article/details/125974279

智能推荐

华云大咖说 | 华云数据助力企业桌面快速上云_华云数据 体验最好的云桌面-程序员宅基地

文章浏览阅读173次。近年来,国家把科技自立自强作为国家发展的战略支撑,越来越多的行业企业将自主创新、自主研发作为发展的重中之重,以此增强企业的核心竞争实力。在今年发布的政府工作报告中,也对推动科技创新发展提出了众多战略要求。华云数据是中国云计算独角兽,自成立以来,始终坚持以技术创新为根本,坚持自主研发,至今已获得500余项知识产权。已经具备支持多芯多栈的解决方案,在复杂的混合IT架构背景下,可以为用户提供完整的数据中心云化、云上办公、信创转型和公有云方案。随着5G、云计算、大数据等技术的快速发展,以及移动办公、远程协作等._华云数据 体验最好的云桌面

解决coursera课程国内打不开的问题_coursera在中国能看吗-程序员宅基地

文章浏览阅读564次。2021.8.8亲测有效https://zhuanlan.zhihu.com/p/77631369_coursera在中国能看吗

JOJ 1055: Cog-Wheels 解题报告 _cog-wheels解题思路-程序员宅基地

文章浏览阅读744次。这个题太恶心,一开始给想错了。光把分子分母看能否分别表示是不对的一组反例 8 3 14 表示 7:12 这时就需要加倍数,14:24却是可以分开表示的。 代码写的不好,有几个地方可以改动的 老规剧 题意: 给定一些数字 ,运用这些数字作乘除运算,看能不能得到指定比例。 分析 : 1. 把所给的数字能得到的最_cog-wheels解题思路

C++ 计算多边形的面积,计算IOU_c++计算多边形面积-程序员宅基地

文章浏览阅读8.7k次,点赞10次,收藏52次。//求任意多边形的面积/*语法:result = polygonarea(vector<Point>&polygon, int N);参数:polygon:多变形顶点数组N:多边形顶点数目返回值:多边形面积注意:支持任意多边形,凹、凸皆可多边形顶点输入时按顺时针顺序排列*/#include <iostream>#include <vector>using namespace std;typedef struct Point{..._c++计算多边形面积

echarts自适应问题,echarts中怎么改变字体单位实现自适应_echarts字体适应-程序员宅基地

文章浏览阅读1w次,点赞24次,收藏49次。最初想着怎么给echarts设置vw单位或者rem,echart中怎么把legend的单位设置为vw或者rem来使表格自适应,后面发现行不通。项目中使用px-to-vw包,将所有px转为对应的vw,所有可以根据相同比例进行缩放,做到自适应效果。但是使用了echarts图表,图表中的fontSize和legend的大小等默认都是px单位。当屏宽为4K屏时,其他地方元素字体等都能适应,但是echa..._echarts字体适应

Python Web 之 Flask-SQLAlchemy 框架_flask-sqlalchemy 类似于mybatisplus的封装-程序员宅基地

文章浏览阅读689次,点赞2次,收藏3次。文章目录数据库 ORM 框架MySql-8安装Windows 免安装版图形化客户端关于破解Flask-SQLAlchemyCRUD操作`Create` 插入数据`Read` 查询数据`Update` 修改数据`Delete` 删除数据定义实体关系欢迎关注我的公众号:编程之路从0到1数据库 ORM 框架什么是ORM?即Object-Relationl Mapping,它的作用是在关系型数据库和..._flask-sqlalchemy 类似于mybatisplus的封装

随便推点

ORBSLAM3 的改进_orb改进-程序员宅基地

文章浏览阅读9.6k次,点赞17次,收藏114次。周六看到了ORBSLAM3的源码,安装运行后看了一下其代码结构,因为加IMU的部分是针对之前的ORB-VI, 因此大家可以参考jinpang的LearnORBVI可以更纯粹地学习视觉+IMU的组合;这篇文章主要是针对其在Tracking线程做出的改动,尤其是添加Atlas后对Tracking部分的影响,LoopClosing和MapMerging的部分会在后面的分析中讲到,有错误也欢迎各位指正。ORBSLAM3相对于ORBSLAM2做出的主要改动:1. Atlas: 用于保存很多琐碎的地图;主要_orb改进

livechart 只显示 y 值_图片显示特斯拉上海超级工厂 Model Y 生产线已基本准备就绪 - 特斯拉...-程序员宅基地

文章浏览阅读49次。10 月 23 日消息,据国外媒体报道,在一期的 Model 3 生产线建成投产之后,特斯拉上海超级工厂今年开始了二期的大规模建设,主要是建设 Model Y 的生产厂房,所生产的 Model Y 计划在明年开始交付。从特斯拉最新公布的图片来看,在经过大半年的建设之后,上海超级工厂 Model Y 生产厂房的外部施工已基本结束,内部的生产线也已基本准备就绪。特斯拉是在新近发布的三季度财报中,公布上..._特斯拉工厂python

Kettle 参数、变量和全局变量(kettle.properties)使用-程序员宅基地

文章浏览阅读3.2k次。有没有能统一管理一个参数,然后让所有的transformation和job都可以读到呢? 答案是有 1.首先,打开.kettle\kettle.properties,直接在里面定义,(注意这个文件需要与spoon.bat放在同一个目录下面)比如: paramName=to_char(sysdate,'yyyymmdd') 这里支持数据库函数,说的更直白点,就..._kettle.properties

NewPhy.-揭秘优势种dominant species-程序员宅基地

文章浏览阅读2.4k次。Title:Demystifying dominant speciesJournal:New PhytologistReceived: 4 May 2018Accepted: 17 Fe..._优势种功能性状的变化,对生态系统功能

基于 Spring Boot + Vue 实现的可视化拖拽编辑的大屏项目-程序员宅基地

文章浏览阅读1k次。大家好,今天给小伙伴们分享一个基于 SpringBoot + Vue 实现的可视化拖拽编辑的大屏项目;# 简介这个是一个开源的一个BI平台,酷炫大屏展示,能随时随地掌控业务动态,让每个决策都有数据支撑。多数据源支持,内置mysql、elasticsearch、kudu驱动,支持自定义数据集省去数据接口开发,支持17种大屏组件,不会开发,照着设计稿也可以制作大屏。三步轻松完成大屏设计:配置数据源--..._vue实现拖拽可视化

使用百度sdk定位相关参数设定_百度android sdk设置精度优先-程序员宅基地

文章浏览阅读3.3k次。使用百度sdk定位相关参数设定_百度android sdk设置精度优先

推荐文章

热门文章

相关标签