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解决了什么问题,以及它的基本用法的更多相关文章

  1. 解决全局变量共享---C语言的extern关键字用法

    在调试程序时,有一个参数需要在多个函数之间传递,因为是作为调试参数,不想将参数引入到函数中. 很自然的想到使用全局变量来表示这个公共参数,工程代码的结构如下: main.c test.c test.h ...

  2. Android VideoView未解决,动态读取权限、BottomNavigationView的用法

    昨天想写的,但是因为Video的毛病,是真找不出为啥了.百度也没用,学长也不清楚. 百度了那么久,大概得出结论,电脑的视频是不能用它来播放的... ..经过两天的奋斗,我居然搞定了,我的视频终于出来了 ...

  3. window.addEventListener来解决让一个js事件执行多个函数

    可能你也碰到过这种情况,就是在js的代码中用了window.onload后,可能会影响到body中的onload事件.这时就要用window.attachEvent和window.addEventLi ...

  4. 006-线程同步解决【ReentrantLock】

    一.解决方案 004-线程同步问题引出.同步问题解决.死锁.生产者与消费者 通过以上文章可知,通过原子性AtomicLong .以及内部锁(synchronized)机制可以解决线程安全问题.以下是一 ...

  5. 痛苦的版本对齐(3) cygwin下的路径引用(sed解决篇)

    上次问题(见http://www.cnblogs.com/yvivid/p/3546649.html),.depend信息路径错误的问题. 主要尝试了,在(虚拟机下构建)linux下编译,确实没有问题 ...

  6. 程序异常崩溃后用windbg辅助调试解决的经验 以及 堆栈问题调试经验

    1,程序异常崩溃后用windbg辅助调试解决的经验  状况:我的程序调用别人的库做 文件写入工作. 在这一过程中出现异常,程序崩溃. 经反复检查,认为自己的程序没有错,但无法判断在别人库里哪里有错. ...

  7. 【VS开发】MFC学习之 解决StretchBlt()图片缩放绘图失真

    vc中位图伸缩函数StretchBlt在对图片进行缩放时会造成严重的图片失真.在了解解决方法前先巩固下StretchBlt的用法: StretchBlt 函数功能:函数从源矩形中复制一个位图到目标矩形 ...

  8. Java中常用的解决乱码的几种方法

    乱码有时候是一个非常让人头疼的问题,这里就总结一下常用的解决乱码的方法. 只知道的用法,却不明白为什么这么用…… 一. 在Java代码中: request.setCharacterEncoding(& ...

  9. JavaScript状态模式及状态机模型

    这是一篇,我自己都看不完的文章... 文章大体就两部分: 状态模式的介绍 状态机模型的函数库javascript-state-machine的用法和源码解析 场景及问题背景: 我们平时开发时本质上就是 ...

  10. 还在一个模块打天下嘛?你知道引入Jetpack架构后,你的App会发生哪些奇妙的变化吗?

    前言 上篇文章我给大家分享了我对Android架构的理解,从思想层面去讲述架构的演进过程.很多小伙伴读完后拍手叫好,表示还想听我讲一下对Jetpack 架构的看法,本着帮人帮到底的精神,今天我将再次动 ...

随机推荐

  1. SQL优化(二)-- 慢查询

    1.慢查询日志 MYSQL的慢查询日志是Mysql提供的一种日志记录方式,它主要是用来记录mysql执行语句过程中,响应时间超过阀值的语句,这个阀值可以通过long_query_time去指定,比如说 ...

  2. Python代码相似度计算(基于AST和SW算法)

    代码相似度计算将基于AST和Smith-Waterman算法 AST (抽象语法树) AST即Abstract Syntax Trees,是源代码的抽象语法结构的树状表示,树上的每个节点都表示源代码中 ...

  3. 省市县树形结构打印-.netCore控制台程序

    using CityJson;using Dapper;using Newtonsoft.Json;{ using (var db = DbHelper.Db()) { //数据格式 //code_p ...

  4. Linux/UNIX Shell $PATH变量

    Linux/UNIX的shell在执行命令时,会查找路径$PATH来录找命令. 1:$PATH是一个以冒号分隔的目录列表,执行命令时,会在列表中查找. 2:命令可以是SHELL脚本也可以是可执行文件, ...

  5. [OpenCV-Python] 22 直方图

    文章目录 OpenCV-Python:IV OpenCV中的图像处理 22 直方图 22.1 直方图的计算,绘制与分析 22.1.1 统计直方图 22.1.2 绘制直方图 22.1.3 使用掩模 22 ...

  6. day08-优惠券秒杀04

    功能03-优惠券秒杀04 4.功能03-优惠券秒杀 4.7Redis优化秒杀 4.7.1优化分析 现在来回顾一下优惠券秒杀业务的两个主要问题: (1)首先是对优惠券的扣减,需要防止库存超卖现象: (2 ...

  7. spring xml配置中引用java配置不能用ClassPathXmlApplicationContext

    现在的目的是想测试在xml配置中引用java配置的bean CD唱片的接口: package v4.c2; public interface CompactDisc { void play(); } ...

  8. 学node 之前你要知道这些

    初识nodejs   19年年底一个偶然的机会接到年会任务,有微信扫码登录.投票.弹幕等功能,于是决定用node 来写几个服务,结果也比较顺利.   当时用看了下koa2的官方文档,知道怎么连接数据库 ...

  9. #Python pandas库,读取模块,代码笔记

    日常数据清洗中,利用python清洗的第一步就是读取对应文件,今天一起复盘一下数据读取环节的常规操作. csv和xlsx格式读取类似,所以用csv做案例 X-MIND图

  10. 【python爬虫】bilibili每周必看页面视频图片爬取

    此博客仅作为交流学习 对于使用bilibili上学习和娱乐的小伙伴们有时会看到视频博主发布的视频封面好看想要得到,但是苦于没有方法,这次我用python来爬取bilibili每周必看页面视频图片. 首 ...