【Android基础】Activity及其生命周期

一、Activity使用概要

1. Activity概述

 Activity是android四大组件中使用最多的,通常也是我们新手接触的第一个组件。Activity是android提供的一个组件,主要用于提供一个界面(窗口)与用户交互,比如:打电话,发邮件,显示地图等等,这些我们在屏幕上看到的界面都是由Activity这个组件所提供的,所以Activity就像一个视图(View)。每个Activity都会有一个window,并且在这个window上面绘制界面,这个window通常是填充满整个屏幕的,当然,也可以比屏幕更小或是悬浮在其他window上。通常,一个应用(app)有多个Activity,并且都会有一个特定的Activity,这个Activity作为这个app的主Activity。当用户点击手机上的应用图标启动app的时候,系统首先会启动这个主Activity,然后,其他的Activity看具体情况启动(每个Activity都可以启动其他Activity)。

2. Activity使用intent-filters

 通常,我们在使用Activity的时候,需要先在清单文件里面注册,注册的时候我们可以给我们的Activity添加intent-filters(意图过滤器)。

 在清单文件里面注册Activity,除了主Activity需要两个必要的intent-filters节点的子节点的时候,其他的Activity通常不需要intent-filters,而需不需intent-filters还可以看我们应用的Activity的使用范围。

 当我们的Activity需要暴露给其他应用共享时(如手机上的相机),我们就需要给我们的Activity提供一个intent-filters,这是因为,其他的应用通常不能通过显示启动的方式来启动我们的Activity,只好通过隐式启动来启动我们的Activity了。而当我们的应用的Activity没必要让其他的应用启动时,我们就不必给我们的Activity设置intent_filters,因为,通常我们通过显示启动自己应用的Activity。

主Activity在清单文件中注册如下(通常):

<activity android:name=".MainActivity" android:icon="@drawable/app_icon">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

上面intent-filter的两个子节点及其名字属性标识了这个Activity是这个应用的主Activity。其他的子节点及Activity属性可以查看官方文档。

3. Activity的启动方式

上面说到了我们可以通过显示启动和隐式启动Activity,这里就简单说一下这两种启动方式:

1、显示启动

 使用这种方式的前提是我们已经知道了要启动的Activity的名字(类全名),然后直接通过下面的方式启动:

Intent intent = new Intent(MainActivity.this,TestActivity.class);
...
startActivity(intent);

中间省略表示我们可以给intent设置一些东西,比如添加数据…

2、隐式启动

 使用这种方式启动就表示我们要启动的Activity比较模糊,但是我们知道我们要启动的Activity的目的(或者说那个Activity可以达到我们的目的),即要启动的Activity具有某种功能或特征,启动方式如下:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

这表示我们启动一个可以发送邮件的Activity(只要可以发送邮件就行,具体是哪个我们并不关心)。

4. Activity之startActivityForResult()

有的时候我们启动一个Activity的目的并不是开启第二个界面,而是为了当前的这个Activity需要获取另外一个Activity交互的结果,比如:当我们当前的Activity需要让用户选择一个联系人的时候,我们可以在当前的Activity启动选择联系人的Activity,当用户选择好联系人后,将返回的结果给我们的当前Activity,这样,当前这个Activity就可以接着往下工作了。

代码示例:

private void pickContact() {
    // Create an intent to "pick" a contact, as defined by the content provider URI
    Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
    startActivityForResult(intent, PICK_CONTACT_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
    if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
        // Perform a query to the contact's content provider for the contact's name
        Cursor cursor = getContentResolver().query(data.getData(),
        new String[] {Contacts.DISPLAY_NAME}, null, null, null);
        if (cursor.moveToFirst()) { // True if the cursor is not empty
            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
            String name = cursor.getString(columnIndex);
            // Do something with the selected contact's name...
        }
    }
}

当我们调用pickContact()方法之后,系统会启动一个选择联系人的Activity,当用户选择好联系人后,系统会调用onActivityResult(int requestCode, int resultCode, Intent data)方法将选择的结果封装到Intent对象中返回给当前的那个Activity。这个方法的另外两个参数也非常好理解,试想一下,既然我们启动Activity是为了获得结果,那么我们肯定可以多次调用startActivityForResult()启动返回不同结果的Activity,那么多次调用这个方法后系统都会回调onActivityResult(),那么我们就要根据请求码(requestCode)标识我们是哪一次启动的Activity,根据resultCode标识我们启动Activity获取结果的情况,这是完成一个任务,当然有可能任务完成了,有可能任务取消,也有可能任务失败了。

5. 结束Activity

 有两个方法可以结束Activity,一个是调用finish()方法结束一个Activity,一个是调用finishActivity()结束一个预先启动的Activity。

注意:通常不要自己调用结束Activity的方法结束Activity,因为这样对用户不友好,而由系统管理。

二、 Activity生命周期

熟悉掌握Activity的生命周期对于构建强壮的灵活的应用是非常重要的。

1. Activity的状态

Activity的生命周期受其他Activity的影响及系统影响,Activity总共有3种状态:

  1. 运行中(Resumed):当Activity位于前台并获得用户焦点时呈现Runing状态;
  2. 暂停状态(Paused):当其他的Activity运行在前台并获得用户焦点,但部分透明或是没有覆盖整个屏幕,所以之前的那个Activity还是可见的,被暂停,内存中还保留着原来的那个Activity的对象(还依附在窗口管理器中),这个对象也保留着所有的信息。当系统内存过低的时候,系统会杀死被暂停的Activity;
  3. 停止状态(Stopped):当其他的Activity运行在前台获取了用户焦点而且完全完全覆盖了这个Activity,那么这个Activity处于停止状态,但系统内存中还保留着这个Activity的对象,这个对象也保留着所有的信息,但已经不可见了,当系统在其他地方需要内存的时候会被系统杀死。

处于Paused和Stoped状态的Activity,系统可以杀死它释放它所占的内存,也可以通过调用finish()方法结束它,或是它所在的进程被杀死。被杀死的Activity再下次重新打开的时候就必须调用onCreate()方法重新创建这个Activity了。

2. Activity生命周期回调方法

当Activity的状态在那个三个状态中变化时,系统会回调它的一系统方法,这样我们就可以在适当的方法中做一些事情,如:恢复Activity的状态,注册注销广播等等。系统给我们提供了6个关于生命周期中回调的方法。

  1. onCreate():当Activity第一次被创建的时候会被调用,我们总是在这个方法里面做一些初始化的工作,如:初始化view,绑定数据等等。这个方法带有一个Bundle类型的参数,这个参数保存了之前保存下来的Activity的状态信息。这个方法只会,总是会调用onStart()方法。
  2. onRestart():第一次启动Activity不会调用,当Activity从不见停止状态到再次启动会调用,其后紧跟onStart()的调用。
  3. onStart():当Activity从不见到变成可见的时候回调用,该方法调用后可能会调用onResume()(可见后立即紧跟调用)或是onStop()(当Activity从可见变为不可见),
  4. onResume():当Activity即将可以和用户交互的时候会被调用,此时,这个Activity一定位于当前Activity栈的栈顶,其后紧跟onPause()方法的调用。
  5. onPause():当其他的Activity位于栈顶变为Resumed状态,则这个Activity会调用onPause(),通常,我们需要在这个方法里面做一些工作,如保存数据,停止动画,释放可能会消耗cpu的资源的资源等等。其后如果这个Activity又回到前台,那么接下来会调用onResume(),也可能这个Activity变为不可见,那么就会调用onStop()方法。
  6. onStop():当Activity不可见的时候会调用(其他已存在或是新的Activity完全覆盖了这个Activity),其后,如果这个Activity即将再次回到和用户交互,那么就会调用onRestart()方法,也可能这个Activity即将被销毁,那么就会调用onDestory()。
  7. onDestroy():当Activity即将要被销毁的时候会调用(调用finish()或是系统临时是否了该Activity对象的内存)。可以通过isFinish()方法判断Activity是否被销毁。

借用官网的一张图加深理解:

这里写图片描述

注意:

  1. 重新Activity生命周期方法的时候,在执行我们自己的代码前一定要先调用父类的该方法。
  2. 我们可以在onPause()方法中保存当前Activity的状态和数据,并且释放消耗cpu资源的资源(停止动画,停止线程…),因为这个方法之后,这个Activity也许会被销毁,也许会重新回到运行状态。
  3. Activity完整的生命周期从onCreate()开始,到onDestory()结束,所以,我们可能是在onCreate()中开启线程下载东西,然后在onDestory()中结束线程。
  4. Activity可见的生命周期从onStart()开始到onStop()结束,在这个阶段中,Activity可以被用户看见并和用户交互,所以这个阶段中,我们可以保持必要的资源,如注册广播和注销广播等等。
  5. Activity获得焦点位于前台的生命周期从onResume()开始到onPause()结束。这两个过程可能会频繁地切换。

3. Activity生命周期示例

当一个Activity(A)启动另外一个Activity(B)的时候涉及到了Activity的生命周期的变化,同时如果被启动的Activity B是一个窗口Activity,那么A的生命周期也会有所不同。

  1. 新启动的Activity的生命周期:onCreate()->onStart()->onResume()
  2. A启动一个正常的Activity(不是窗口) B,则A的生命周期:onPause()->onStop()
  3. A启动一个窗口Activity C,则A的生命周期:onPause()
  4. 普通Activity B返回,则A的生命周期:onRestart()->onStart()->onResume()
  5. 窗口Activity C返回,则A的生命周期:onResume()

上面的结果我们可以从Activity是否可见以及是否处于前台来分析:

  • 由于启动一个正常的Activity B会将原来的Activity A遮挡,导致A不可见,所以原来的Activity A会调用onPause()->onStop()而处于停止状态,此时如果新启动的Activity B返回,由于原来的Activity A处于停止状态,所以这个时候A就需要重新启动即onRestart()->onStart()->onResume()
  • 如果启动的Activity C是一个窗口,那么这时C并不会将A全部遮挡,A还是可见的,所以不会调用onStop,而当C返回时,A也就不会调用OnRestart及onStart了。
  • onStart() —> 启动 —> 可见
  • onStop() — > 停止 – -> 不可见
  • onResume() —> 恢复 —> 位于前台,可交互
  • onPause() —> 暂停 —> 位于后台,不可交互

4. 保持Activity的状态

 当一个Activity被暂停或是停止了,但它的对象还保存在内存中,所以,为了当这个Activity再次启动回到运行状态的时候还可以维持用户原来对这个Activity做的改变,我们需要保存Activity的状态。

系统在销毁Activity前会调用onSaveInstanceState()方法,因此,我们可以利用这个方法里面的参数保存我们要保存的信息。该参数是一个Bundle对象,所以,里面存储的数据是键值对形式。然后,系统我们可以在onCreate()方法或onRestoreInstanceState()方法里面恢复Activity的状态(这两个方法都有一个Bundle类型的参数)

这里写图片描述

通常,用户按返回键结束掉的Activity没必要保存状态。而由于屏幕旋转导致屏幕配置发生变化的时候通常需要保存和恢复状态。

5. 处理屏幕配置的变化

 设备屏幕在运行中可能改变,比如:屏幕旋转,弹出软键盘等等,所以,系统为了让Activity适应新的屏幕配置,系统会先调用onDestroy()结束Activity,然后调用onCreate()重建Activity。这样做的目的是为了让我们的应用根据屏幕的变化选择相应的资源文件(如横屏状态下的layout和竖屏状态下的layout)以便做的自动适配屏幕变化。

 由于屏幕的配置可能在程序运行中改变,所以,通常,最好的方法是在onSaveInstanceState()中保存原来Activity的状态并在onRestoreInstanceState()或onCreate()中恢复Activity的状态。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值