再谈Activity生命周期

随着用户进入、离开、再进入等动作,我们的Activity不停的在其生命周期的几个状态之间来回切换,比如,当用户点击桌面上的应用程序图标时,我们的主Activity被启动,这时,系统会调用一系列的生命周期回调函数来完成Activity的创建及显示工作;当用户切换到另一个Activity的时候,当前Activity的一系列生命周期方法又被调用。在程序的执行过程中,Activity会在其生命周期的各个状态之间不停的转换。根据我们所需的Activity的复杂度,我们可能不需要实现所有的生命周期回调函数,但是我们有必要理解每一阶段是怎么一回事,这样方可确保我们所写程序的表现符合用户的期望,一般来说,我们应该遵守以下几点基本要求:

  • 当用户由于接到一电话或者其他原因切换到另一个程序时,我们的程序不能出问题
  • 当用户不再使用我们的程序的时候,我们的程序不应该继续消耗有价值的系统资源
  • 当用户离开一段时间然后又回到程序时,先前的进度不能丢失
  • 当由于屏幕方向切换时我们的程序能够表现正常(实现方法后边会说)

一个Activity只会有六种状态,Created、Started、Resumed、Paused、Stopped、Destoryed。其中Activity在Created、Started、Destoryed这三个状态上不会做停留,也就是说从这一状态很快会过渡到下一状态。另外三种状态如果想发生转移的话是需要有条件触发的,这三种状态的含义如下:

  • Resumed:此时Activity在前景并且可以和用户进行交互
  • Paused:此时Activity部分可视,但是不能和用户交互
  • Stopped:此时用户完全不可视(被全部遮挡了),但是依然会被保留到内存中

从Activity被Create到其被Destory,可以将这一过程比作爬阶梯型的金字塔,其中Resumed状态为金字塔的顶端。从创建到可视并可以获得焦点,经历三个步骤就从金字塔的一边爬到了顶端;当用户离开当前Activity的时候,可比作下金子塔,当然以后还有可能会再次回退到顶部,这个类比过程可用下图说明:

 

启动Activity:我们应该为我们的应用程序设定一个主Activity,做到这点很容易,只需在清单文件(AndroidManifest.xml)中对要设定为主Activity的组件做如下声明:

<activity android:name=".MainActivity" android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

其中的<intent-filter>中的action和category必须做如上声明,只要其中有一个不满足,则在我们的程序图标就不会出现在系统桌面上。

要想启动一个Activity,我们必须为其提供onCreate()方法,这也是唯一一个我们必须实现的方法,在这个方法中我们应该做一些在Activity的生命周期中只需执行一次的事情,比如设置用户界面、初始化一些类作用域的变量等。如下下边的例子所示,在onCreate()中这是了界面,初始化了将要在程序代码中引用的控件。

TextView mTextView; // Member variable for text view in the layout

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Set the user interface layout for this Activity
    // The layout file is defined in the project res/layout/main_activity.xml file
    setContentView(R.layout.main_activity);
    
    // Initialize member TextView so we can manipulate it later
    mTextView = (TextView) findViewById(R.id.text_message);
    
    // Make sure we're running on Honeycomb or higher to use ActionBar APIs
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        // For the main activity, make sure the app icon in the action bar
        // does not behave as a button
        ActionBar actionBar = getActionBar();
        actionBar.setHomeButtonEnabled(false);
    }
}

在调用onCreate函数之后,会很快调用onStart(),当调用这个函数时,Activity就已经可以在屏幕上看到了;在这个状态也不会过多停留(如前所述),紧接着调用onResume(),这个函数执行之后,Activity便可以和用户交互了,这是一个Activity遍完成了启动过程,并且会停留在这一状态,除非有其他的事情发生,比如用户点击了某个按钮启动了另外一个Activity。启动过程共三步,可用下图表示:

销毁Activity:正如onCreate()是被第一个调用的,onDestory()是被最后调用的,调用这个函数表明系统将会把这个Activity从内存中移除。大多数情况下我们没有必要重写这个方法,因为大部分的清理工作应该在onPause()和onStop()方法中完成,但是,如果我们在onCreate()中启动了某些线程之类,会长期占用系统资源,如果不清理会造成内存泄露,那么我们应该在onDestory()中将其关闭。如下所示,在onDestory()中,关闭了调试时用的方法调用痕迹。

@Override
public void onDestroy() {
    super.onDestroy();  // Always call the superclass
    
    // Stop method tracing that the activity started during onCreate()
    android.os.Debug.stopMethodTracing();
}

一般情况下,系统会在调用onPause()和onStop()之后调用onDestory(),但是有一特例,如果我们在onCreate()中调用了finish(),则不会调用onPause()和onStop(),直接调用onDestory()。

Pausing和Resuming:当用户执行其它动作将当前Activity部分遮挡的时候,就会进入Paused状态,这时会调用onPause()方法,这意味着用户离开当前Activity,并且有可能不会再回来了,在这个方法中,我们应该做如下工作:

  • 停止那些消耗CPU工作
  • 保存那些尚未存储的更改,当然,只能保存用户希望我们保存的,比如编辑了一部分的邮件。但是我们不应该在这个函数中执行一些费时的工作,不如写数据库,像这类比较耗时繁重的工作应该在onStop()中完成,这样做的目的是希望可以快速的过渡到下一个状态。
  • 释放一些在暂停状态下不用的资源,不如广播接受者等

下面的例子在onPause()中释放了一个相机资源:

@Override
public void onPause() {
    super.onPause();  // Always call the superclass method first

    // Release the Camera because we don't need it when paused
    // and other activities might need to use it.
    if (mCamera != null) {
        mCamera.release()
        mCamera = null;
    }
}

当用户从暂停状态返回时,将会调用onResume(),这里我们应该将在onPause()中释放的资源重新获取,注意一点,这个方法在启动过程中也是会被调用的。如下示例为在onResume()中重新获取了相机资源:

@Override
public void onResume() {
    super.onResume();  // Always call the superclass method first

    // Get the Camera instance as the activity achieves full user focus
    if (mCamera == null) {
        initializeCamera(); // Local method to handle camera init
    }
}

Pausing和Resuming过程可用下图详细说明:

Stopping and Restarting:合理的处理这一过程是很重要的,因为我们应该让用户感到应用程序一直都没有关闭,先前的进度还在。下面有几个典型的情况需要用到stop然后restart的过程:

  • 用户切换到另一个程序,当前Activity被stop,然后用户有回到当前程序,这时我们应该restart离开时的Activity。
  • 用户在当前Activity执行了一个动作使得启动了另一个activity,当前Activity被stop,另一个Activity被启动,过了一会儿,用户按了返回键,当前ACtivity应该被restart。
  • 用户接了一个电话后,先前的Activity应该被restart。

当onStop()被调用,意味着当前Activity完全不可见,这是我们应该释放几乎是全部的系统资源,因为在某些极端情况下,系统有可能都不会调用onDestory()来终止当前Activity,所以我们一般在这里释放那些比较费时的释放工作,比如说写数据库。

当用户再次将Activity从Stop状态激活时,将会调用onRestart(),之后也会调用onStart()。其实,onRestart()并不是很常用,因为其后会调用onStart(),而onStart()无论是在Activity第一次启动,还是从Stop状态恢复都会被调用,通常所有的工作都会在onStart()中完成。

整个Stop和Restart过程可以用下图说明:

Recreate Activity:重建Activity。如果Activity是正常终止的话,那么这个过程不需要;但是如果是由于系统资源不足,而终止了那些当前不用的Activity,那么系统会记住这一情况,当用户再次回到该Activity的时候,系统会利用销毁这个Activity时记录的一个Buble对象进行重建。若要实现这个重建,需要我们重写onSaveInstanceState()方法,这个方法返回一个Buble对象。当这个Activity被“非预期”销毁时,系统会调用这个方法,然后如果确实需要重建的时候,将会把这个方法传递给onCreate()和onRestoreInstanceState()。如下例:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
    
    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

因为在重建的时候,这个Buble会被传递给俩个方法,onCreate()和onRestoreInstanceState(),所以我们选其中一个实现即可,只不过onCreate()在第一次创建时也会被调用,所以需要判断一下Buble是否为空,以此来区分这俩种状态,在onRestoreInstanceState()中就不存在这样的情况。重建过程如下图:

这篇博客中的内容来自对Android官方文档的理解,更权威的内容请参考官方文档。鉴于本人也是新手,纰漏之处在所难觅,欢迎批评指正。本人QQ联系方式:750516366,欢迎交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值