Lifecycle解决了什么问题,以及它的基本用法
1.为何要引入Lifecycle?
我首先来举个大家都比较常见的例子:我们在android开发的时候,经常需要在页面的onCreate()方法中对组件进行初始化,在onPause()方法中停止组件,而在页面的onDestroy()方法中对组件进行资源回收工作。这样的工作非常繁琐,会让页面和组件间的耦合度变高。但这些工作又不得不做,因为可能会引起内存泄漏。
这里我先给出普通组件和系统组件这两个名词的概念,系统组件是指Activity/Fragment,Service和Application;普通组件是指我们将代码按照功能或作用进行封装的组件。我们希望对自定义组件/普通组件的管理不依赖于页面生命周期的回调方法,同时又在页面生命周期发生变化的时候及时收到通知。这在组件化和架构设计中显得尤为重要。为此,Google引入了Lifecycle作为解决方案,Lifecycle可以帮助开发者创建可感知生命周期的组件。这样,组件就可以在其内部管理自己的生命周期,降低了和页面的耦合度。
接下来,从三个方面来讲解一下Lifecycle的用法。
2.使用Lifecycle解耦Activity和组件
案例分析:假设有这样一个需求,在用户打开某个页面的时候,获取用户当前的地理位置,离开这个页面的时候,停止获取。面对这个需求,我们可以这样写代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化位置管理器
initLocationManager();
}
@Override
protected void onResume() {
super.onResume();
//开始获取用户的地理位置
startGetLocation();
}
@Override
protected void onPause() {
super.onPause();
//停止获取用户的地理位置
stopGetLocation();
}
}
从以上的代码可以看出,获取地理位置这个需求的实现和页面的生命周期息息相关。如果我们想要把这个功能独立成一个组件,那么必须得感知页面的生命周期变化。Lifecycle是如何解决这个问题的呢?Jetpack为我们提供了两个类LifecycleOwner(被观察者)和LifecycleObserver(观察者),即通过观察者模式实现对页面生命周期的监听。
通过查看ComponentActivity源码,可以得知该类实现了LifecycleOwner接口,并重写了getLifecycle()方法。如下图所示:


LifecycleOwner接口只有getLifecycle()这一个方法,LifecycleOwner正是通过该方法实现观察者模式的。所以,从以上源码可以得知,ComponentActivity已经帮我们实现了被观察者应该实现的那一部分代码,我们只需要实现观察者应该实现的那一部分代码即可。实现的方式也很简单,就是让自定义组件实现DefaultLifecycleObserver接口,然后将其添加为观察者就行了。
public class MyLocationListener implements DefaultLifecycleObserver {
private LocationManager manager;
private Context context;
private OnLocationChangedListener onLocationChangedListener;
public MyLocationListener(Activity context, OnLocationChangedListener onLocationChangedListener) {
manager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
this.context=context;
this.onLocationChangedListener=onLocationChangedListener;
}
@Override
public void onPause(@NonNull LifecycleOwner owner) {
DefaultLifecycleObserver.super.onPause(owner);
Log.i("MyLocationListener","stopGetLocation");
}
public interface OnLocationChangedListener{
void onChanged(double latitude,double longitude);
}
@Override
public void onResume(@NonNull LifecycleOwner owner) {
DefaultLifecycleObserver.super.onResume(owner);
Log.i("MyLocationListener","startGetLocation");
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
manager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1, new LocationListener() {
@Override
public void onLocationChanged(@NonNull Location location) {
onLocationChangedListener.onChanged(location.getLatitude(),location.getLongitude());
}
});
}
}
public class MainActivity extends AppCompatActivity {
private TextView tv_display;
private MyLocationListener myLocationListener;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_display = findViewById(R.id.tv_display);
myLocationListener=new MyLocationListener(this, new MyLocationListener.OnLocationChangedListener() {
@Override
public void onChanged(double latitude, double longitude) {
tv_display.setText(""+latitude+","+longitude);
}
});
getLifecycle().addObserver(myLocationListener);
}
}
就这么简单!Lifecycle完美解决了组件对页面生命周期的依赖问题,使得组件可以自行管理生命周期。当将自定义组件作为页面生命周期的观察者时,页面处于哪个生命周期,就会回调DefaultLifecycleObserver接口中的同名方法。是的,就是同名方法!
public interface DefaultLifecycleObserver extends FullLifecycleObserver {
@Override
default void onCreate(@NonNull LifecycleOwner owner) {
}
@Override
default void onStart(@NonNull LifecycleOwner owner) {
}
@Override
default void onResume(@NonNull LifecycleOwner owner) {
}
@Override
default void onPause(@NonNull LifecycleOwner owner) {
}
@Override
default void onStop(@NonNull LifecycleOwner owner) {
}
@Override
default void onDestroy(@NonNull LifecycleOwner owner) {
}
}
可以看到这些方法名前面加了一个default关键词,就是你可以有选择性的重写所需要的方法,而不需要全部重写。是不是很简单?
3.使用LifecycleService解耦Service与组件
这个类继承自Service并且实现了LifecycleOwner接口, 它也提供了getLifecycle()方法供我们使用。我们只需要继承这个类即可。下面给出代码:
public class MyService extends LifecycleService {
private MyServiceObserver myServiceObserver;
public MyService(){
myServiceObserver=new MyServiceObserver();
getLifecycle().addObserver(myServiceObserver);
}
}
MyServiceObserver同样要实现DefaultLifecycleObserver接口,和前面的一模一样,这里不再赘述。
4.使用ProcessLifecycleOwner监听应用程序的生命周期
具有生命周期的系统组件除了Activity,Fragment,Service外,还有Application。很多时候,我们会遇到这样的需求:我们想知道应用程序当前处在前台还是后台,以便作出不同的处理。这个功能用ProcessLifecycleOwner实现起来十分简单,和前面非常的相似。不过这次我们想要观察的是整个应用程序,因此需要在Application中进行相关代码的编写。
public class AppApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppApplicationObserver());
}
}
AppApplicationObserver也是要实现同样的接口:DefaultLifecycleObserver。
public class AppApplicationObserver implements DefaultLifecycleObserver {
private String TAG=getClass().getName();
@Override
public void onCreate(@NonNull LifecycleOwner owner) {
Log.i(TAG,"onCreate");
DefaultLifecycleObserver.super.onCreate(owner);
}
@Override
public void onStart(@NonNull LifecycleOwner owner) {
Log.i(TAG,"onStart");
DefaultLifecycleObserver.super.onStart(owner);
}
@Override
public void onResume(@NonNull LifecycleOwner owner) {
Log.i(TAG,"onResume");
DefaultLifecycleObserver.super.onResume(owner);
}
@Override
public void onPause(@NonNull LifecycleOwner owner) {
Log.i(TAG,"onPause");
DefaultLifecycleObserver.super.onPause(owner);
}
@Override
public void onStop(@NonNull LifecycleOwner owner) {
Log.i(TAG,"onStop");
DefaultLifecycleObserver.super.onStop(owner);
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
Log.i(TAG,"onDestroy");
DefaultLifecycleObserver.super.onDestroy(owner);
}
}
应用程序创建的时候调用onCreate()方法并只调用一次,在前台的时候分别调用onStart()和onResume(),应用程序在后台的时候调用onPause()和onStop()。不过需要注意的是,onDestroy()永远不会调用,系统不会分发调用这个事件。
Lifecycle的用法到这里就基本讲解完毕了,怎么样,感觉如何?
Lifecycle解决了什么问题,以及它的基本用法的更多相关文章
- 解决全局变量共享---C语言的extern关键字用法
在调试程序时,有一个参数需要在多个函数之间传递,因为是作为调试参数,不想将参数引入到函数中. 很自然的想到使用全局变量来表示这个公共参数,工程代码的结构如下: main.c test.c test.h ...
- Android VideoView未解决,动态读取权限、BottomNavigationView的用法
昨天想写的,但是因为Video的毛病,是真找不出为啥了.百度也没用,学长也不清楚. 百度了那么久,大概得出结论,电脑的视频是不能用它来播放的... ..经过两天的奋斗,我居然搞定了,我的视频终于出来了 ...
- window.addEventListener来解决让一个js事件执行多个函数
可能你也碰到过这种情况,就是在js的代码中用了window.onload后,可能会影响到body中的onload事件.这时就要用window.attachEvent和window.addEventLi ...
- 006-线程同步解决【ReentrantLock】
一.解决方案 004-线程同步问题引出.同步问题解决.死锁.生产者与消费者 通过以上文章可知,通过原子性AtomicLong .以及内部锁(synchronized)机制可以解决线程安全问题.以下是一 ...
- 痛苦的版本对齐(3) cygwin下的路径引用(sed解决篇)
上次问题(见http://www.cnblogs.com/yvivid/p/3546649.html),.depend信息路径错误的问题. 主要尝试了,在(虚拟机下构建)linux下编译,确实没有问题 ...
- 程序异常崩溃后用windbg辅助调试解决的经验 以及 堆栈问题调试经验
1,程序异常崩溃后用windbg辅助调试解决的经验 状况:我的程序调用别人的库做 文件写入工作. 在这一过程中出现异常,程序崩溃. 经反复检查,认为自己的程序没有错,但无法判断在别人库里哪里有错. ...
- 【VS开发】MFC学习之 解决StretchBlt()图片缩放绘图失真
vc中位图伸缩函数StretchBlt在对图片进行缩放时会造成严重的图片失真.在了解解决方法前先巩固下StretchBlt的用法: StretchBlt 函数功能:函数从源矩形中复制一个位图到目标矩形 ...
- Java中常用的解决乱码的几种方法
乱码有时候是一个非常让人头疼的问题,这里就总结一下常用的解决乱码的方法. 只知道的用法,却不明白为什么这么用…… 一. 在Java代码中: request.setCharacterEncoding(& ...
- JavaScript状态模式及状态机模型
这是一篇,我自己都看不完的文章... 文章大体就两部分: 状态模式的介绍 状态机模型的函数库javascript-state-machine的用法和源码解析 场景及问题背景: 我们平时开发时本质上就是 ...
- 还在一个模块打天下嘛?你知道引入Jetpack架构后,你的App会发生哪些奇妙的变化吗?
前言 上篇文章我给大家分享了我对Android架构的理解,从思想层面去讲述架构的演进过程.很多小伙伴读完后拍手叫好,表示还想听我讲一下对Jetpack 架构的看法,本着帮人帮到底的精神,今天我将再次动 ...
随机推荐
- Nvidia Tensor Core-WMMA API编程入门
1 WMMA (Warp-level Matrix Multiply Accumulate) API 对于计算能力在7.0及以上的CUDA设备,可以使用CUDA C++ API调用Tensor Cor ...
- Java学习笔记09
1. 多态 1.1 多态 多态是指同一种行为具有多种不同的表现形式. 前提 有继承或者实现关系 有方法重写(没有重写多态就没有意义) 父类引用指向子类对象 格式 父类类型 变量名 = new 子类 ...
- 微服务 - Redis缓存 · 数据结构 · 持久化 · 分布式 · 高并发
本篇内容基于 Redis v7.0 的阐述:官网:https://redis.io/ 本篇计划用 Docker 容器辅助部署,所以需要了解点 Docker 知识:官网:https://www.dock ...
- 《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(14)-Charles过滤网络请求
1.简介 在日常工作测试中,经常要抓包看请求的request,response是不是传的对,返回的字段值对不对,众多的请求中看得眼花缭乱,如何找到自己想要的请求,那么我们就需要过滤请求.Charles ...
- fzy&czn生日赛t1 CZN
fzy&czn生日赛t1 CZN 膜拜hybb首杀 目录 fzy&czn生日赛t1 CZN 题目背景 题目描述 分析 my code wnag's code 题目 题目背景 有一天,c ...
- HashMap实现原理和自动扩容
HashMap实现原理: JDK1.7:数组+单向链表(头插) 在并发情况下头插可能出现循环链表(死循环)问题.原因:因为头插,在新数组中链表的元素顺序发生了变化, 如上图,假设线程1在扩容,刚刚调整 ...
- 机器视觉基本理论(opencv)
1. 什么是图像采样 采样是按照某种时间间隔或空间间隔,将空间上连续的图像变换成离散点的操作称为图像采样 2. 什么是图像分变率 采样 得到的离散图像的尺寸称为图像分辨率.分辨率是数字图像可辨别的最小 ...
- PaddlePaddle 自动求导
自动求导 在 PaddlePaddle 中使用自动求导来计算导数. 要求:$ f(x)=\sin{x} $,绘制 \(f(x)\) 和 \(\dfrac{\mathrm{d}f(x)}{\mathrm ...
- 2020-11-02:go中,s:=make([]string,10);s=append(s,“test“);fmt.Println(s[0]),打印什么?
福哥答案2020-11-02: 打印空字符串.s:=make([]string,10),s中已经有10个元素,append元素,s就有11个元素了.前10个元素没初始化,就是10个空字符串,最后1个字 ...
- 使用doop识别最近commons text漏洞的污点信息流
作者:vivo 互联网安全团队 - Chen Haojie 本文基于笔者对doop静态程序分析框架源代码和规则学习,并结合对目前漏洞公开技术细节的学习,修改增强doop app only模式下的分析规 ...