Activity的生命周期

在现在以及以后,我都会把知识点进行整理,为什么呢?虽然不整理也可以,用的时候去百度,百度?呵呵了吧大家,太菜了吧,对,我菜。写文章的目的就是加深自己的记忆,到时候用的时候尽量下笔如有神,哪怕回来看看自己整理的文章,也不要去百度,使自己花个10多分钟多余的时间去搜索答案。还有一方面就是,看着自己开发了这么长时间,居然没有怎么整理发布过博客,感觉没有学到什么东西,看看其他同行都在写自己的整理,心里不是滋味啊,mmp,还是因为一个字 “懒”。好了文章开始前就说这么多,下面就来看看我们今天的基础知识吧,Activity的生命周期和启动模式。

Activity生命周期

系统是通过实现回调方法来管理Activity的生命周期的,在说这些回调方法什么时候会被调用前,先来了解下Activity在整个生命周期中,是以3个状态存在的。

-活动状态: 此Activity位于屏幕前台并且拥有用户焦点。
-暂停状态:另外一个Activity位于屏幕前台并且拥有用户焦点,但是此Activity任然可见。意思就是说当前Activity覆盖在此Activity上,并且当前Activity是部分透明或者没有完全覆盖此Activity,从而使得此Activity仍然可见。此时此Activity是暂停状态,然后是存活的(Activity对象保留在内存中,它保留了所有成员变量和状态,与窗口管理器连接),但是在内存不足的情况下,可能会被系统终止。
-停止状态:另外一个Activity把当前Activity完全覆盖,使此Activity完全不可见(该Activity完全在后台)。此时该Activity是停止状态,但是此时该Activity还是存活状态(Activity对象保留在内存中,拥有所有的状态和成员变量信息,但是未与窗口管理器连接)。不过,他对用户是不可见的,在其他地方需要内存时,该Activity可能被终止。即销毁。
好了了解了Activity在整个生命周期的三种状态后,生命周期就是指上面的三种状态在相互之间转换时,系统会通过各种回调方法来进行通知,我们继续往下看吧。

1.正常情况下的生命周期

所谓正常情况下的生命周期就是,我们平时正常操作手机时,Activity所经历的生命周期。我们先来看看在整个生命周期Activity会回调的方法。
(1).onCreate()方法: 首次创建Activity时会调用,在这个方法里面可以做一些初始化的工作,比如去加载布局文件等。后接onStart()方法。
(2).onRestart()方法:在Activity已经停止(onStop()方法后)并即将再次启动前调用。注意之前Activity已经停止状态并没有销毁时。后接onStart()方法。
(3).onStart()方法:在Activity即将对用户可见之前调用。如果Activity转入前台可见,则后接onResume()方法,如果Activity进入隐藏状态,则后接onStop()方法。
(4).onResume()方法:方法,在Activity即将开始与用户进行交互之前调用。始终后接onPause()方法。
(5).onPause()方法:,当系统即将开始继续另一个Activity时调用,此方法通常用于确认对持久化数据的未保存更改、停止动画以及其他可能消耗CPU的内容。他应该非常迅速的执行所需操作,因为他返回后,下一个Activity才能继续执行。如果此Activity转入前台,则执行onResume()方法,要是转为后台,则执行onStop()方法。
(6).onStop()方法:在Activity对用户不可见时调用。对用户不可见发生的情况一是当前Activity被销毁(执行了finish()方法);二是另外一个Activity完全覆盖了当前的Activity。如果Activity恢复与用户的交互,则后接onRestart()方法。如果Activity被销毁则后接onDestory()方法。
(7).onDestory()方法:在Activity被销毁时调用。这是Activity收到的最后的回调方法。当Activity结束(有人对Activity调用了finish()方法),或者系统为节省控件儿暂时销毁该Activity时,可能会调用他。

以上就是所有的回调方法,一共7个,注意上面三个方法,onPause()、onStop()、onDestory()方法,这三个方法在执行后,都有可能终止承载Activity的进程,画个角度就是说,承载当前Activity的进程被终止时,onPause()方法是一定会被执行的,如果在紧急情况下需要内存,onStop()和onDestory()方法不一定会执行。因此,在onPause()方法中应该像存储设备保存至关重要的数据(面试题问过)。不过不要在onPause()方法中执行太多的操作,不然会影响下一个Activity的执行。而其他的方法都会防止承载Activity的进程被终止。

虽然上面7个方法什么时候运行和之间的切换都描述了,我们还是用官方的一张图来展示下:


生命周期转换图

看了上面7个方法的描述,这张图看起来是不是很爽,很简单。
好了生命周期的回调方法在上面写的很清楚,包括什么时候执行什么方法和下一步具体的操作又会执行什么方法,下面我们就来验证下正常操作Activity的整个生命周期的回调方法。不然上面说个蛋蛋,谁知道上面说的是对是错。结合上面描述我们得到以下的结论:

1.一个Activity从启动到显示,会执行onCreate()-->onStart()-->onResume()。
2.当用户打开新的Activity覆盖 当前Activity时,会执行onPause()-->onStop();如果新的Activity采用了透明主题或者没有完全覆盖之前Activity时(这里的覆盖只是Activity,若是Dialog覆盖了当前Activity就不会对Activity的生命周期产生影响),只会执行onPause(),不会执行onStop()。
3.当用户把不可见的Activity再次回到完全可见(与用户交互)时,会执行onRestart()-->onstart()-->onResume()。
4.当用户把被透明主题的Activity覆盖的Activity再次回到完全可见时(与用户交互),只会执行onResume()。
5.当系统回收一个Activity后,重新打开时,回调与1是一样的。

1.1 代码测试
/**
 * Created by h on 2018/2/6 0006.
 */
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.bt_tosecond_activity).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //跳转到SecondActivity
                startActivity(new Intent(MainActivity.this, SecondActivity.class));
            }
        });


        findViewById(R.id.bt_open_dialog).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //弹出透明的LucencyActivity
                startActivity(new Intent(MainActivity.this, LucencyActivity.class));
            }
        });
        Log.e("TAG", "onCreate()");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e("TAG", "onRestart()");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e("TAG", "onStart()");

    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("TAG", "onResume()");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e("TAG", "onPause()");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e("TAG", "onStop()");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e("TAG", "onDestroy()");
    }
}


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.gh.jiejin">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity" />
        <activity android:name=".LucencyActivity" android:theme="@android:style/Theme.Translucent"></activity>
    </application>

</manifest>

以上代码就是通过两个按钮来启动两个新的Actiivity,注意LucencyActivity采用了透明主题。

1.2 测试结果
  • 运行MainActivity后控制台打印如下:


    启动MainActivity

    因此验证了结论1。

  • 在MainActivity执行代码打开SecondActivity,完全覆盖MainActivity,然后再按返回按钮,使MainActivity重新显示控制台打印如下:


    image.png

    可以看出当显示SecondActivity完全覆盖MainActivity时,依次打印了onPause()-->onStop()。
    当按下返回按键,MainActivity重新显示时,依次执行了onRestart()-->onStart()-->onResume().
    因此证明了结论2和3。

  • 当在MainActivity中打开LucencyActivity时,由于采用了透明主题,MainActivity还是可见的,因此只会打印onPause()方法。这时候,要是再按下返回按键,使MainActivity完全显示时,是不是也会只打印onResume()方法呢,我们这两个操作依次执行,看看控制台是怎样打印的:


    image.png

    可以看出和我们想的完全一样,这里也就验证了结论2和4

  • 我们再看看MainActivity跳转到SecondActivity这个过程,这两个的生命周期方法是怎么回调的
    如下图:


    image.png

    可以看出MainActivity的onPause()方法先调用完成后,然后再开始新的Activity,这也验证了我们之前的分析,不要再onPause()方法中执行太多的操作,不然会影响新的Activity的显示速度。

2 异常情况下的生命周期

2.1说到异常情况下的生命周期,什么样的情况才是异常情况呢,异常情况分为以下两种:

1.系统其他地方需要内存时,从而销毁了某项Activity。优先销毁后台的Activity。
2.资源相关的系统配置发生改变导致Activity被杀死并重新创建。

2.2 异常情况下的生命周期概述

就是说,在以上两种情况下,Activity会先销毁,然后再会重新创建,这个过程的回调方法是onPause()-->onStop()-->onDestory()-->onCreate()-->onStart()-->onResume();这个过程就是异常情况下的生命周期。对于情况1,优先销毁的是后台的Activity,当用户再次切换到该Activity时,该Activity就会重新创建;对于情况2,是在改变了系统的配置信息时(例如手机屏幕方向的切换、键盘可用性及语言)时,当前Activity会被销毁并且马上被创建。

2.2研究异常情况下生命周期的目的:

因为以上两种情况Activity的杀死,基本都是在运行的Activity中发生的,在继续Activity时,因为Activity被销毁了又被重新创建了,之前Activity保存的状态就不存在了,但是用户并不知道Activity的状态变化了,所以我们应该在系统销毁Activity时保存状态(也就是进行的操作),然后再重新创建Activity的时候恢复之前的状态(也就是进行的操作)。

2.3 保存状态和数据的操作

对于以上两种情况而言,保存状态或者数据和恢复状态和数据是完全一致的。系统若是准备销毁Activity时,系统会回调onSaveInstanceState()方法来对Activity的状态信息进行保存,以确保有关Activity的状态的重要信息进行保存,系统在调用onSaveInstanceState()方法后,然后再使Activity易于销毁,在执行onSaveInstance()方法时,系统会像该方法中传入一个Bundle,咱们可以使用这个Bundle对象使用putString()或者putInt()等方法以键值对的形式来保存信息。并且当用户返回该Activity时,该Activity会被重建,并将Bundle对象传递给onCreate()和onRestoreInstanceState(),从这两个方法中的任意一个都可以来提取之前保存的状态和恢复Activiy的状态。如果没有状态要恢复(比如之前销毁前没有进行保存数据,或者第一次启动Activity时),这里系统传入的Bundle对象就是空的。对于情况2与情况1唯一不同的是,情况1重新创建Activity时,是当用户切换到该Activity时重新创建,情况2当系统配置发生变话时,会先销毁然后马上新建Activity,就只有重建Activity的时机不一样而已.信息的保存和恢复过程是一模一样的。

注意
1.并不是在任意Activity销毁前都会调用onSaveInstanceState()方法的,因为这个方法是在异常情况下才会调用,普通的销毁是不会销毁这个方法的,比如按下返回按键是不会调用这个方法的。并且onSaveInstanceState方法是在onStop()方法之前调用的,与onPause()方法没有前后关系,既有可能在onPause()之前调用,也有可能在之后调用。
2.不过,即使您什么都不做,也不实现onSaveInstanceState()方法,Activity的onSaveInstanceState()默认实现也会恢复部分 Activity 状态。具体地讲,默认实现会为布局中的每个View调用onSaveInstanceState()方法,让每个视图都能保存自身的状态,Android 框架中几乎每个小部件都会根据需要实现此方法,以便在重建 Activity 时自动保存和恢复对 UI 所做的任何可见更改,例如EditText部件保存用户输入的任何文本,checkBox 小部件保存复选框的选中或未选中状态。您只需为想要保存其状态的每个小部件提供一个唯一的 ID(通过 )android:id属性)。如果小部件没有 ID,则系统无法保存其状态。
3.由于 onSaveInstanceState()的默认实现有助于保存 UI 的状态,因此如果您为了保存更多状态信息而替换该方法,应始终先调用onSaveInstanceState()的父类实现,然后再执行任何操作。 同样,如果您替换 onRestoreInstanceState()方法,也应调用它的父类实现,以便默认实现能够恢复视图状态。

2.4 代码验证

下面就通过代码来演示下异常情况下的生命周期,因为异常的两种情况下生命周期是一样的,并且由于系统回收Activity不好模拟,我们就模拟在系统配置改变的情况下(屏幕方向改变)来测试,测试的结果说白了就是演示下生命周期的回调方法的调用顺序和观察下保存数据和恢复数据的情况还有一些View自带的恢复效果。代码如下:


   public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);



        Log.e("TAG", "onCreate()");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e("TAG", "onRestart()");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e("TAG", "onStart()");

    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("TAG", "onResume()");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e("TAG", "onPause()");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //可以进行保存一些数据
        outState.putString("data","我保存的data");
        Log.e("TAG","onSaveInstanceState---保存数据data");
    }


    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        //恢复数据
        if(savedInstanceState!=null){
             String data = savedInstanceState.getString("data");
            Log.e("TAG","onRestoreInstanceState---取出数据data="+data);
        }

    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e("TAG", "onStop()");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e("TAG", "onDestroy()");
    }



}

竖屏截图


竖屏.png

横屏截图


横屏.png

控制台打印结果:


控制台打印结果.png
2.5分析结果

可以看出在手机屏幕方向为竖屏时,EditText编写了文字,然后改变手机方向为横屏时,发现EditText编写的文字还在,这就是EditText默认保存了信息状态,我们再来看看在手机屏幕由竖屏转换为横屏时打印的方法,明显时Activity先销毁再重新创建了,在销毁之前,调用onStop()方法之前确实先调用了onSaveInstanceState()方法,我们在这个中我们保存一个字符串信息,然后再重建的Activity显示之前调用了onRestoreInstanceState()方法,并且取出了之前在onSaveInstanceState()方法中保存的字符串。这样就验证了我们上面的分析。最后说一句,我们能不能在系统配置文件改变的时候不重新创建Activity呢?答案是有的,我们可以在Actiivty配置文件中添加android:configChanges=""属性就可以,属性值的填写可以具体查阅参考资料(去百度吧)哈哈,在android Studio会提示出来的,具体每个属性值的意思应该能看出来,想配置多个属性值时,中间用“|”来分隔开即可。


configChanges.png

3总结

以上就是对Activity生命周期的理解,主要是参考官方文档来写的,第一次写文章,写的有点乱,希望不要喷我。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容