外企面试中的7 个 Android Lifecycle 重要的知识点

news2024/10/2 16:28:53

习惯性的每天都会打开 medium 看一下技术相关的内容,偶然看到一位大佬分享和 Android Lifecycle 相关的面试题,觉得非常的有价值。

在 Android 开发中 Android Lifecycle 是非常重要的知识点。但是不幸的是,我发现很多新的 Android 开发对 Android Lifecycle 不是很了解,导致在开发中遇到很多奇怪的问题。

分享这些面试题,不仅仅是为了通过面试,更是为了让 Android 开发者基础更加的扎实,防止在开发中遇到很多奇怪的问题。

面试题一:Launch Fragment by Default

问题:

花几秒钟思考一下,下面的代码有什么问题。

class MainActivity : AppCompatActivity() {

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

        supportFragmentManager
           .beginTransaction()
           .replace(R.id.container, MainFragment())
           .commit()
   }
}

错误的回答

  1. 没有使用 KTX 添加 Fragment
  2. 应该使用 .add 而不是 .replace

正确的回答

如果 Activity 因意外被杀死并被恢复,会再次执行 onCreate() 方法,创建新的 Fragment,因此在栈中会存在 2 个 Fragment。在 Fragment 上的任何操作都可能被执行两次,这将会导致出现奇怪的问题。

为了防止 Activity 因意外被杀死而恢复,导致添加新的 Fragment,所以我们可以使用 stateInstanceState == null 作为判断条件,防止添加新的 Fragment,因此我们可以将上面的代码简单修改一下。

class MainActivity : AppCompatActivity() {

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

        if (savedInstanceState == null) {
            supportFragmentManager
                .beginTransaction()
                .replace(R.id.container, MainFragment())
                .commit()
        }
   }
}

面试题二:Create Fragment with Constructor

问题:

如果往 Fragment 构造函数中添加参数,花几秒钟思考一下,下面的代码会有什么问题?

supportFragmentManager
    .beginTransaction()
    .replace(R.id.container, MainFragment())
    .commit()

class MainFragment(private val repository: Repository): Fragment() {

}    

错误的回答

  1. 我们可以使用 .replace(R.id.container, MainFragment(repository)) 方法来代替
  2. 它不会编译和运行

正确的回答

我们不应该直接用带参数的构造函数实例化任何 Fragment(),如果想使用带参数的构造函数实例化 Fragment(),可以使用 FragmentFactory 解决这个问题,这是在 AndriodX Fragment 1.2.0 中新增加的 API,详情可以查看另外一篇文章 Google 建议使用这些 Fragment 的新特性。

如果不使用 AndriodX Fragment 库,默认情况下系统是不支持的,虽然上面的代码可以正常编译运行,但是在运行过程当中,因为配置更改,导致在销毁恢复的过程中会崩溃,错误信息如下所示。

Caused by: java.lang.NoSuchMethodException: MainFragment.<init>

这是因为系统需要在某些情况下重新初始化它,比如配置更改,例如设备被旋转时,导致 Fragment 被销毁,如果没有默认空的构造函数,系统不知道如何重新初始化 Fragment 实例。

因此,我们总是需要确保实例化 Fragment 的时候有一个空的构造函数。

面试题三:Instantiate ViewModel Directly

ViewModel 是 Jetpack 架构组件成员之一,花几秒钟思考一下,下面的代码会有什么问题?

class MainActivity: AppCompatActivity() {
    private val viewModel = MainViewModel()
}

class  MainViewModel(): ViewModel {

}

错误回答

  1. 没有什么问题,可以正常编译运行
  2. 我们还需要向它注入一些依赖项,例如 MainViewModel (repository)

正确回答

我们不应该直接实例化 ViewModelViewModel 是 Jetpack 架构组件成员之一,意味着它可以在配置更改时存活,例如设备旋转时,它比 Activity 有更长的生命周期。

如果我们在代码中直接实例化 ViewModel,尽管它可以工作,但它将会变成一个普通的 ViewModel,失去原本拥有的特性。

因此,要实例化 ViewModel,建议使用 ViewModel KTX,代码如下所示。

class MainActivity: AppCompatActivity() {
    private val viewMode:MainViewModel by viewModels()
}
  • by viewModels () 会在重新启动或从已杀死的进程中恢复时,实例化一个新的 ViewModel。如果有配置更改,例如设备被旋转时,它将检查 ViewModel 是否已经创建,而不重新创建它

  • ViewModels() 会根据需要自动注入 SavedInstancestate (例如 Activity 中的 SavedInstanceStateIntent),如果我们有其他依赖是通过 Dagger Hilt 注入,它将与 ViewModel 一起使用下面的参数
@HiltViewModel
class MyViewModel @Inject constructor(
    private val repository: Repository,
    savedStateHandle: SavedStateHandle
) : ViewModel {

}

面试题四:ViewModel as StateRestoration Solution

问题:

Jetpack 架构组件提供的 ViewModel 的作用是什么?

class MainActivity: AppCompatActivity() {
    private val viewMode:MainViewModel by viewModels()
    // Some other Activity Code
}

错误回答

ViewModel 是用于状态恢复,例如当 Activity 被杀死并重新启动时,ViewModel 是用来帮助恢复到原始状态。

正确回答

ViewModel 实际上是 google 提供的 Jetpack 架构组件之一,它鼓励 Android 开发者使用 MVVM 设计模式。

它还有其它重要的功能,例如设备旋转时,即使 ActivityFragment 被销毁,它们各自的 ViewModel 仍会保留,Google 在 ViewModel 中提供了一个名为 savedStateHandle 参数,该参数用于保存和恢复数据。

面试题五:LiveData as State Restoration Solution

问题:

Jetpack 架构组件提供的 LiveData 的作用是什么。

// Declaring it
val liveDataA = MutableLiveData<String>()
// Trigger the value change
liveDataA.value = someValue

错误回答:

它的存在是为了确保数据在 Activity 的生命周期中存活。当 Activity 在进程销毁返回时,数据将会自动恢复。

正确回答

LiveData 本身不能在进程销毁中存活。它是一种特殊类型的数据,根据观察者(Activity 或 Fragment)的生命周期来控制其发出的值。

ViewModel 在配置变更后仍然存在,所以 ViewModel 内部的 LiveData 也一样。这确保 LiveData 发射值按照下图控制。

然而 LiveData 本身不能在进程销毁中存活,当内存不足时,Activity 被系统杀死,ViewModel 本身也会被销毁。

为了解决这个问题,Google 在 ViewModel 中提供了一个名为 savedStateHandle 参数,该参数用于保存和恢复数据,以便数据在进程销毁后继续存在。

@HiltViewModel
class MyViewModel @Inject constructor(
    private val repository: Repository,
    savedStateHandle: SavedStateHandle
) : ViewModel {
    // Some other ViewModel Code
}

它是一种增强的机制,可以处理 IntentSavedInstanceState,在以前的时候,这些都是由 Activity 单独处理的。

为了确保 Livedata 保存下来,我们可以在 SavedStateHandle 中检查 Livedata 是否已经创建。

val liveData = savedStateHandle.getLiveData<String>(KEY)

类似地,这也适用于 stateFlow,它可以在进程销毁中存活下来。

val stateFlow = savedStateHandle.getStateFlow<String>(KEY, 0)

因此 LiveData 本身并不是用来恢复数据的。

面试题六:When is The View Destroyed But Not the Instance

问题:

在 Activity 或 Fragment 通常会有一个视图。你能给我提供一个场景,实例的视图被破坏了,但实例(例如 Activity 或 Fragment)还存在。

错误回答

  1. 当配置发生变化时(例如设备旋转)
  2. 当内存不足时,App 在后台运行,进程会杀死 App

正确回答

实际上 Activity 总是与其视图一起被销毁。因此,在 Activity 中没有 onDestroyView () 生命周期方法。

只有在 Fragment 中有 onDestroyView () 生命周期方法。在大多数情况下 Fragment 和它的视图一起被销毁。

但是通过 Fragment transaction 用一个 Fragment 替换另一个 Fragment 时,栈下面的 Fragment 仍然存在,但是它的视图被破坏了。

当一个 Fragment 被另一个 Fragment 替换时,会调用 onDestroyView () 方法,但不会调用 onDestroy ()onDetect () 方法。

正因为这种复杂性,在使用 Fragment 时,会遇到许多奇怪的问题。和 Fragment 相关的问题,将会在后面的文章中分享。

问题七:Lifecycle Aware Coroutine

在 App 中使用协程,如何确保它们的生命周期可感知。

错误回答

  1. 对于普通视图,只需在 ActivityFragment 中使用 lifecycleScope,在 ViewModel 中使用 viewModelScope
  2. 对于组合视图,需要使用 stateFlow 中的 collectAsState() 方法,因为当可组合函数不活动时,它不会收集

正确回答

对于普通视图,即使 lifecycleScope 是可用的,它在 ActivityFragment 的整个生命周期中都处于活动状态。因为有时我们希望某些场景只在 onStart()onResume() 之后处于活动状态。

为此,我们需要在 lifecycleScope 中使用像 repeatOnLifecycle 这样的 API 提供额外的作用域。

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.stateFlowValue.collect {
            // Do something
        }
    }
}

它们的变体如下图所示。

对于组合视图 collectAsState() 不会确保在组合函数处于活动状态时安全使用数据,它也不会停止继续发送 StateFlow,这会导致资源浪费。

为了确保只在 ActivityFragment 处于正确的生命周期时,例如在 onStart () 之后发出,我们需要使用 collectAsStateWithLifecycle ()stateFlow 中的 WhileSubscribed (...)

当我们在研究 collectAsStateWithLifecycle() 源码时,发现它也在使用 repeatOnLifecycle(…)

更多Android 知识点可参考

Android 性能调优系列

Android 车载学习指南

Android Framework核心知识点笔记

Android 八大知识体系

Android 中高级面试题锦

第一章 Android 高频面试之必考Java基础
1.面向对象和面向过程的区别
2.面向对象的特征有哪些
3.解释下Java的编译与解释并存的现象
4.简单介绍下JVM的内存模型
5.简单介绍下Java的类加载器
6.谈一下Java的垃圾回收,以及常用的垃圾回收算法
7.成员变量和局部变量的区别
8.Java 中的方法重写(Overriding)和方法重载(Overload)的含义
9.简单介绍下传递和引用传递
10.为什么重写 equals 时必须重写 hashCode 方法
11.接口和抽象类的区别和相同点是什么
12.……

第二章 Android 面试之必问Android基础
1.Activity
2.Fragment
3.Service
4.BroadcastReceiver
5.ContentProvider
6.Android View知识点
7.Android进程
8.序列化
9.Windows
10.消息机制
11.RecyclerView优化

第三章 Android 面试之必问高级知识点
1.编译模式
2.类加载器
3.Android Hook
4.代码混淆
5.NDK
6.动态加载

第四章 Android 面试之必问性能优化
1.启动优化
2.UI渲染优化
3.内存优化
4.网络优化
5.耗电优化
6.安装包优化

第五章 Android 面试之开源库分析
1.HTTP与缓存理论
2.OKHttp
3.Retrofit
4.Glide
5.EventBus
6.……

第六章 算法面试题汇总
1.排序
2.二叉树
3.链表
4.栈 / 队列
5.二分搜索
6.哈希表
7.堆 / 优先队列
8.二叉搜索树
9.数组 / 双指针
10.贪心
11.字符串处理
12.动态规划
13.矩阵
14.二进制 / 位运算
15.……

第七章 Android面试之Flutter相关面试题全解析
1.Dart部分
2.Flutter 部分

第八章 Android面试之必问设计模式
1.请列举出在 JDK中几个常用的设计模式?
2.什么是设计模式?你是否在你的代码里面使用过任何设计模式?
3.Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
4.在 Java 中,什么叫观察者设计模式(observer design pattern)?
5.使用工厂模式最主要的好处是什么?在哪里使用?
6.举一个用 Java 实现的装饰模式(decorator design pattern)?它是作用于对象层次还是类层次?
7.在 Java 中,为什么不允许从静态方法中访问非静态变量?
8.设计一个 ATM 机,请说出你的设计思路?比如设计金融系统来说,必须知道它们应该在任何情况下都能够正常工作。
9.在 Java 中,什么时候用重载,什么时候用重写?
10.举例说明什么情况下会更倾向于使用抽象类而不是接口?
11.设计模式六大原则
12.设计模式的分类
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

准备pmp考试第13天

准备pmp考试第13天 32 31 感觉答案和题目没有关系 感觉答案和题目没有多大关系&#xff0c;题目看越多 错的越多&#xff0c;答案不按照问的回答&#xff0c;跑题了 30 29 28 PMP 激励&#xff1a;为某人采取行动提供了理由。 提高团队参与决策的能力并鼓励他们独立工作。这里面…

go - rune类型

一、简介 rune类型是Go语言的一种特殊数字类型。 rune是类型int32的别名&#xff0c;在所有方面都等急啊于它&#xff0c;用来区分字符值跟整数值。 Go语言通过rune处理中文&#xff0c;支持国际化多语言。 字符串由字符组成&#xff0c;字符的底层由字节组成&#xff0c;而一…

码神之路项目总结(二)

目录 一、登录功能 & 二、获取用户信息& 三、退出登录 四、登录拦截&#xffe5; 五、ThreadLocal保存用户信息&#xffe5; 六、文章详情 一、登录功能 & 请求接口&#xff1a; 思路&#xff1a; 1、首先接收前端传过来的用户名和密码&#xff0c;判断值是否为空…

知识图谱认知智能理论与实战----------第二章 知识图谱模式设计

文章目录一. 知识图谱模式二. 模式与本体三. 本体概论I. 模式与本体辨析II.本体的构成要素III.实体分类IV.实体分类四. 六韬法I. 场景II. 复用III. 事物IV. 联系V. 约束VI. 评价一. 知识图谱模式 实体&#xff1a;eg&#xff1a;法国&#xff0c;巴黎…关系&#xff1a;eg&…

深度学习入门(三十六)计算性能——异步计算、自动并行

深度学习入门&#xff08;三十六&#xff09;计算性能——异步计算、自动并行前言计算性能——异步计算教材1 异步计算1.1 通过后端异步处理1.2 小结2 自动并行2.1 基于GPU的并行计算2.2 并行计算与通信3.3 小结前言 核心内容来自博客链接1博客连接2希望大家多多支持作者 本文…

一起Talk Android吧(第四百一十三回:使用三角函数绘制正弦波)

文章目录整体思路图形讲解示例程序注意事项各位看官们&#xff0c;大家好&#xff0c;上一回中咱们说的例子是"Math类常用方法介绍",这一回咱们介绍的例子是使用三角函数绘制正弦波。闲话休提&#xff0c;言归正转&#xff0c;让我们一起Talk Android吧&#xff01; …

leetcode-每日一题-1710-卡车上的最大单元数(简单,哈希,暴力)

今天的这道题其实很好读懂&#xff0c;因为很容易可以看出来暴力求解&#xff0c;但其实还是隐藏一个hash求解法很巧妙&#xff0c;因为我在很久之前就用过hash解答过这样类似的题&#xff0c;所以这个题也是可以使用的&#xff0c;可以看看我第二个hash解法 目录 暴力效率(效…

SBF vs. 火柴大王

生活中的一切都建立在自信之上。”Ivar Kreuger1929年10月28日&#xff0c;瑞典商人Ivar Kreuger出现在《时代》杂志的封面上。 他是当时美国最受关注的人物之一&#xff0c;因为他富有、有权势、神秘。Kreuger控制着四分之三的火柴生产和销售&#xff0c;在全球35个不同国家拥…

wy的leetcode刷题记录_Day43

wy的leetcode刷题记录_Day40 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2022-11-15 前言 今天时间比较多而且题目比较简单&#xff0c;应该能写三四道题。 目录wy的leetcode刷题记录_Day40声明前言1710. 卡车上的最大单元数题目介…

Spectacle源码编译方法

一、简介 Spectacle 是一个用于抓取桌面截图的简单应用程序。它可以抓取整个桌面、单个显示器、当前活动窗口、鼠标所在的窗口或是屏幕上的一块矩形区域的图像。截取的图像可被打印、发送到其他应用程序进行处理、或是直接保存下来。 Spectacle是archlinux wiki中推荐KDE使用…

刘二大人CNN

10.卷积神经网络&#xff08;基础篇&#xff09;_哔哩哔哩_bilibili 0、前一部分 卷积层 和 subsampling 叫做Feature Extraction特征提取器&#xff0c;后一部分叫做classification 1、每一个卷积核它的通道数量要求和输入通道是一样的。这种卷积核的总数有多少个和你输出通…

SpringBoot+Vue项目医院挂号系统的设计与实现

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JDK版…

2.6 自定义srv python

功能介绍 以自定义数据类型为基础&#xff0c;完成一个节点作为服务器&#xff0c;另一个节点接收传送两个数字到服务端&#xff0c;服务端计算后反馈到客户端进行打印输出 1、工作空间 1.1 创建工作空间lee_ws mkdir -p ~/lee_ws/src cd ~/lee_ws/src/ catkin_init_worksp…

leetcode134.加油站 贪心法求解 (c++版本)

题目描述 题目比较长&#xff0c;明确以下这点就可以 gas数组是当前下标i加油站所能加的油cost数组是从当前下标i加油站到下一加油站所消耗的油那么gas [i]与cost [i] 的大小就决定了车辆能否从当前加油站出发到达下一加油站 上面三点非常重要是能正确做出题目的必须要求 其实…

字符流,编码表,字符流写数据,字符流读数据

文章目录前言字符流编码表字符串中的编码解码问题字符流写数据字符流读数据总结前言 因为近期考试原因&#xff0c;还有自身惰性的问题&#xff0c;小编最近停更了一段时间&#xff0c;随之而来的罪恶感让我又开启了自学与创作之路&#xff0c;学习这么久&#xff0c;自己虽然…

来源稳定的l2逐笔接口数据去哪找?

l2逐笔接口的逐笔数据的最初来源均是从交易所获取&#xff0c;其授予了一些信息服务商L2非展示数据接口转发权限&#xff0c;其中包含了逐笔成交、逐笔委托等数据。使用时&#xff0c;通常是从信息商处购买&#xff0c;比如同花顺、万得、国泰安等等。那么小编认为通过交易所授…

mysql中find_in_set()函数的使用及in()用法详解

MySQL手册中find_in_set函数的语法解释&#xff1a; FIND_IN_SET(str,strlist) str 要查询的字符串 strlist 字段名 参数以”,”分隔 如 (1,2,6,8,10,22) 查询字段(strlist)中包含(str)的结果&#xff0c;返回结果为null或记录 假如字符串str在由N个子链组成的字符串列表strli…

Linux:rpm与yum(内含:1.rpm介绍+2.卸载rpm包+3.安装rpm(应用案例)+4.yum(应用案例))

1.rpm介绍使用: 实例&#xff1a;查看当前系统是否安装了 firefox &#xff0c;操作如下&#xff1a; 解释&#xff1a; 名称&#xff1a;firefox 版本号&#xff1a;91.11.0-2 使用操作系统&#xff1a;el7.centos.x86_64 表示centos.x的64位系统。 查询软件包是否安装&#…

跨境电商卖家必知的9个圣诞节营销技巧

关键词&#xff1a;跨境电商卖家、圣诞节营销 圣诞节——对跨境电商卖家来说是非常重要的促销节日。根据以往的经验&#xff0c;您或许已经有了初步的促销想法&#xff0c;想知道您今年的跨境电子商务营销策略是否正确&#xff1f;为您整理了跨境电商卖家必须注意的营销技巧&am…

TiDB数据库架构——TiDB Server

TiDB Server架构 TiDB Server 是SQL层&#xff0c;无状态&#xff0c;启动多个TiDBServer&#xff0c;均匀分摊&#xff0c;解析SQL&#xff0c;获取真实数据。 Protocol Layer、&#xff1a;负责客户端的连接。 Parse、Compile&#xff1a;负责SQL语句的解析和编译&#xff…