原文地址:Jetpack架构组件学习(1)——LifeCycle的使用 | Stars-One的杂货小窝
要看本系列其他文章,可访问此链接Jetpack架构学习 | Stars-One的杂货小窝
最近有时间了,准备入坑Jetpack架构,第一篇就学个简单的
LifeCycle,可以帮助开发者创建可感知生命周期的组件。
为什么需要LifeCycle组件?
在很多情况下,我们需要在Activity的相关生命周期中进行相关的初始化操作,比如上一节说到的EventBus,需要在OnCreate()和onDestroy()方法中进行绑定和解绑,我们可以使用此组件来简化操作(下面的例子即是使用LifeCycle去简化EventBus绑定Activity的操作)
LifeCycle的本质原理就是观察者模式,其中有类LifecycleOwner(被观察者)和接口LifecycleObserver(观察者),通过观察者模式,即可实现对页面生命周期进行监听,从而减低代码耦合度
这里提下:
Support Library 26.1.0及其以后的版本(含androidx),Activity和Fragment已经实现了LifecycleOwner接口所以,我们可以直接在Activity 和Fragment中使用
getLifecycle()方法来获取lifecycle对象,来添加观察者监听。
我是直接使用了androidx版本,所以基本使用是无需导入额外的依赖
由于Activity和Fragment实现了LifecycleOwner接口,所以,使用我们只需要创建我们的观察者对象,与Activity进行绑定即可
下面以EventBus的初始化来讲解下使用方法
前面也说到了,LifeCycle提供了一个接口类LifecycleObserver,这个接口里没有任何的方法,我们需要要定义个类去实现它,即可让该类成为一个LifeCycle观察者类
我们需要让一个类去实现此接口,由于EventBus需要绑定Activity对象,所以我们需要类提供一个构造方法来接收Activity对象
class EventBusInitiator(val context: Context) : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun register() {
EventBus.getDefault().register(context)
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun unregister() {
EventBus.getDefault().unregister(context)
}
}
那我们实现了接口类,如何让Lifecycle回调我们的方法呢?这里Lifecycle设计就和EventBus有些异曲同工之妙了,也是提供注解的方式,从而Activity在进入对应的生命周期会回调参数
OnLifecycleEvent注解里的参数只接收对应的事件,事件有以下7种类型
ON_CREATE 匹配Activity的onCreate事件ON_START 匹配Activity的onStart事件ON_RESUME 匹配Activity的onResume事件ON_PAUSE 匹配Activity的onStop事件ON_STOP 匹配Activity的onStop事件ON_DESTROY 匹配Activity的onDestroy事件ON_ANY 可以匹配任何的事件(每次Activity的生命周期发生变化,都会调用一次)前6种就是和Activity中的生命周期保持对应,最后一种有点迷,不知道具体是在哪种情况下使用的
PS:在这篇文章中提到Android 架构组件之 LifeCycle详解 - SegmentFault 思否,有两种方式用来实现LifeCycle的监听
Lifecycle.java文档中是建议使用第一种方式,随着Java8成为主流,注解的方式会被弃用。
这里我也没细找文档去研究,也不知道是不是这回事,就我个人感觉使用注解的方式会比较舒服,智者见智仁者见仁吧
在上面实现LifecycleObserver接口后,我们就有个类,当Activity生命周期发生改变的话,就会将事件分发给类中,前提是我们得让Activity注册这个类的对象,代码如下所示
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_event_bus)
lifecycle.addObserver(EventBusInitiator(this))
}
PS:如果是Java,是通过
getLifecycle()方法获取LifeCycle对象

效果与之前的例子一样,点击按钮即可改变文字
LifeCycle中的状态有以下5种类型:
Lifecycle.State.CREATEDLifecycle.State.DESTROYEDLifecycle.State.RESUMEDLifecycle.State.STARTEDLifecycle.State.INITIALIZEDINITIALIZED状态表示的是初始化完成,但onCreate()周期未开始的状态
而之后CREATED状态,标明是onCreate()周期已结束的状态,后面的依次类推
可以参考下面的LifeCycle状态改变和事件的解析图:

判断的话我们可以使用LifeCycle对象的currentState状态,如下代码:
//直接一个判断就完事了
if (lifecycle.currentState == Lifecycle.State.INITIALIZED) {
}
//状态至少要是CREATED
lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)
进阶使用中,需要引入依赖
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
上述的只讲了Activity和Fragment的使用方法,如果我们想要Service中想要生命周期解耦,可以使用LifecycleService,其父类是Service,只不过里面已经实现了LifecycleOwner接口,所以用法是基本一样的
我们使用Android Studio快速新建一个Service


然后修改代码为下述代码:
class MyService : LifecycleService() {
val TAG = "MyService"
init {
lifecycle.addObserver(MyServiceObserver())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
//开启服务就开启个线程
Log.d(TAG, "onStartCommand: 执行")
thread {
for (i in 0..5) {
Log.d(TAG, "线程打印: $i")
Thread.sleep(1000)
}
}
return super.onStartCommand(intent, flags, startId)
}
}
class MyServiceObserver() : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun create() {
Log.d("MyService", "Service中的oncreate方法执行了");
}
}
Service的生命周期和上述Activity的例子一样,这里不再赘述,日志打印如图所示
PS:记得在Activity中使用startService开启服务哦

想起来,之前还没写过Service的学习笔记? 之后有空补上
除了上面的情况,有时候我们需要判断下APP是处于前台或后台,这个时候就可以使用ProcessLifecycleOwner,具体用法如下
需要我们自定义一个application,然后在其中注册观察者即可
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(MyApplicationObserver())
}
}
class MyApplicationObserver : LifecycleObserver{
//在应用程序的整个生命周期中只会被调用一次
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate(){
Log.e("application","Application onCreate方法执行了");
}
//在应用程序在前台出现时被调用
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart(){
Log.e("application","Application onStart方法执行了");
}
//在应用程序在前台出现时被调用
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume(){
Log.e("application","Application onResume方法执行了");
}
//在应用程序退出到后台时被调用
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause(){
Log.e("application","Application onPause方法执行了");
}
//在应用程序退出到后台时被调用
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop(){
Log.e("application","Application onStop方法执行了");
}
//永远不会被调用,系统不会分发调用ON_DESTROY事件
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy(){
Log.e("application","Application onDestroy方法执行了");
}
}
PS:记得在AndroidManifest中使用我们的这个自定义Application

日志输出如下图所示:

我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po