惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
爱范儿
爱范儿
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Y
Y Combinator Blog
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
Martin Fowler
Martin Fowler
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
M
MIT News - Artificial intelligence
博客园 - Franky
V
Visual Studio Blog
I
InfoQ
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
博客园 - 司徒正美
L
LangChain Blog

博客园 - gcg0036

亚信仨月印象(国庆时再写) 博客搬家了! log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "org.apache.log4j.Appender" variable. 模板引擎Crox用法大全(更新版) Apache Tomcat Maven Plugin 参数大全(Tomcat 6) Apache Tomcat Maven Plugin MyEclipse 2015 CI 12 无限试用 sshe源码分析——权限管理的后台部分 sshe源码分析——全局架构 无聊的三月终于过去了 failed to initialize monitor thread 在Android项目中的测试类点击"run as JUnit test"出错 Interacting with Other Apps Saving Data Adding the Action Bar Building Your First App The AndroidManifest.xml File handlebars简单用法 高性能跨语言模板引擎Crox
Managing the Activity Lifecycle
gcg0036 · 2015-03-08 · via 博客园 - gcg0036

http://www.cnblogs.com/gcg0036/p/4321271.html

与其他在应用程序中由main()函数作为开端不同,Android系统的启动代码是在一个Activity的实例通过调用对应其生命周期的特定阶段的特定回调方法中进行。

正确使用你的Activity生命周期函数去保障应用程序的良好表现,必须注意很多方面,包括下面的内容:

当用户接听电话或者转去另外一个应用程序时,不要让程序崩溃。
当用户没有激活使用它时,不消耗宝贵的系统资源。
当用户离开你的应用程序并在稍后的时间返回,不会丢失用户的进度。
当用户屏幕在横向与纵向旋转切换时,不会崩溃或者丢失用户进度。

image 

只有最上面三种状态程序可以长时间驻留:

Resumed状态

在这种状态下,该Activity在前台运行,用户可以与它进行交互。(有时也简称为“running”状态。)

Paused状态

在这种状态下,该Activity被部分遮蔽(被其他在前台的半透明或不覆盖整个屏幕的活动遮住)。此状态不接受用户输入,并且不能执行任何代码。

Stopped状态

在这种状态下,该活动是完全隐藏,不可见的,它被认为是在后台。虽然停止,活动实例和所有成员变量如状态信息将被保留,但不能执行任何代码。
 

其他的状态(created状态和started状态)都是非常短暂而且系统通过调用函数使得非常快地转到下一状态。

你必须在onCreate()方法中操作一些在整个生命周期内只会调用一次的程序启动逻辑内容。

例如,可以在onCreate()方法中定义用户界面的或者初始化一些类变量的内容。

一旦onCreate()方法执行完毕,系统会迅速地执行onStart()方法和onResume()方法。您的Activity永远不会停留在 Created或者Started状态中。当onStart()方法被调用之后,Activity将会变成可见,但是onResume()方法会迅速被调用,并且Activity会维持在Resumed状态直到一些事情发生,例如接到电话,或者用户导航到另一个Activity中,或者屏幕被关闭了

onDestroy()函数作为Activity从内存中完全销毁去除的最后一个信号。大多数的应用程序并不需要使用到这个函数,因为局部类的引用将会和 Activity一起销毁,而一些清理工作,主要也是在onPaused()和onStop()中。然而,如果你的Activity包含了有在 onCreated()或者其他持续性运行的资源在后台线程行运行,您就应该在onDestroy()方法中清除掉它们,而避免内存泄露。

注意:一般来说,系统会在调用onPause()方法和onStop()之后才调用onDestory()方法,但是,有一种情况是例外的,那就是在你在 onCreate()方法中调用finish()方法。在一些情况下,你的Activity作为一个临时决定的操作对象而去启动另外一个Activity 时,你可能需要在onCreate()方法中调用finish()方法去销毁Activity,在这种情况中,系统会直接调用onDestroy()方法而不用再去调用其他的生命周期函数。

在应用程序正常时,当前的Activity有时会因为其他可视化组件阻塞(obstructed)而导致Activity暂停。例如,当打开一个半透明(semi-transparent)的活动(比如,对话框),先前的Activity就会暂停。 只要这个Activity仍然是部分可见,它就一直处于暂停状态。

当Activity进入暂停状态,系统调用Activity中的onPause()方法,这个方法会停止当前正在进行的操作,比如暂停视频播放,同时保存那些有可能需要长期保存的信息。如果用户返回处于暂停状态的Activity,系统会恢复那些数据并执行onResume()方法。

image

通常应该在onPause()回调方法里面完成以下操作:

  • 停止会耗费CPU的动画或者是其他正在运行的操作。
  • 提交没有保存的改变,但是仅仅是在用户离开时期待保存的内容(例如邮件草稿)。
  • 释放系统资源,例如广播接收器, 传感器(如GPS), 或者是其他任何会影响到电量的资源。

通常,不能使用onPause()来保存用户改变的数据 (例如填入表格中的个人信息) 到永久磁盘上。

仅仅确认用户期待那些改变能够被自动保存的时候(例如书写邮件草稿时)才可以

然而,应该避免在onPause()时执行CPU密集的工作,例如写数据到数据库,因为它会导致切换到下一个activity变得缓慢(那些重负荷的操作应该放到onStop()方法中完成)。

如果activity实际上是要被Stop,为了切换的顺畅应该减少在OnPause()方法里面的工作量。

Note:当Activity处于暂停状态,Activity实例是驻留在内存中的,并且在Activity 恢复的时候重新调用。因而不需要在恢复到Resumed状态的一系列回调方法中重新初始化组件。

当用户把一个Activity从Paused状态恢复,系统会调用onResume()方法。

需要注意的是,系统每次调用这个方法对应的activity都处于最前台,包括第一次创建的时候。所以,在实现onResume()方法时应该初始化那些在onPause方法里面释放掉的组件,并执行那些activity每次进入恢复状态都需要的初始化动作 (例如开始动画与初始化那些只有在获取用户焦点时才需要的组件)。

在activity生命周期中,恰当的停止与重启activity是很重要的,这样能确保用户感知到程序的存在并不会丢失他们的进度。在下面一些关键的场景中会涉及到停止与重启:

  • 用户打开“最近使用的程序(Recent Apps)”的菜单并从当前app切换到另外一个app,这个时候先前的app是被停止的。如果用

户通过“主屏幕加载图标(Home screen launcher icon”或“最近使用的程序(Recent Apps)”重新回到这个app,则activity会重启。

  • 用户在当前的app里面执行启动一个新的activity的操作时,当前activity会在第二个activity被创建后停止。如果用户点

击back按钮,之前的activtiy会被重启。

  • 用户在运行app时接受到一个来电通话。

Activity类提供了onStop()方法与onRestart()方法用于在activity停止与重启时进行调用。和暂停状态时部分阻塞用户接口不同,停止状态时UI不可见并且用户的焦点转移到另一个activity中。

注意:因为系统在Activity停止时会在内存中保存了Activity实例,所以很多时候不需要实现onStop()方法与 onRestart()方法,甚至是onStart()方法。 因为大多数的Activity相对比较简单,Activity会自动正常停止与重启,只需要使用onPause()来停止正在运行的动作并断开系统资源链接。

image

当activity调用onStop()方法时,该activity不再可见并且应该释放所有不再需要的资源。一旦activity停止了,系统可能会摧毁activity的实例以回收内存,甚至,系统会不执行activity的onDestroy()回调方法而直接杀死你的app进程, 因此需要使用onStop()来释放资源,从而避免内存泄漏。

当Activity已经停止,Activity对象会保存在内存中,并且在Activity恢复的时候被重新调用到。不需要在恢复到Resumed state状态前重新初始化那些被保存在内存中的组件。系统同样保存了每一个在布局中的视图的当前状态,如果用户在EditText组件中输入了文本,也会被保存,因此不需要保存与恢复它。

注意:即使系统会在Activity停止的时候销毁这个Activity,系统仍然会保存视图对象(如文本编辑框中的文本)到一个Bundle中,并且在用户返回这个Activity时恢复他们

onStart()方法在每次Activity可见时都会被调用。onRestart()方法则是只在Activity从stopped状态恢复时才会被调用

应该使用onStart()作为onStop()所对应的方法。

由于会在onStop方法里面做释放资源的操作,而onDestory方法则是最后去清除那些可能导致内存泄漏的地方,因此需要确保那些线程都被Destroy并且所有的操作都被停止

警告:Activity会在每次旋转屏幕时被Destroy与Recreate

默认情况下, 系统使用Bundle实例来保存每一个视图对象中的信息(例如输入EditText中的文本内容)。

为了可以保存额外更多的数据到saved instance state,在Activity的声明周期里面需要一个添加的回调函数onSaveInstanceState()

image

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);
}

警告:必须要调用onSaveInstanceState()方法的父类实现,这样默认的父类实现才能保存视图状态的信息。

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);
 
    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

当Activity在被Destory后进行重建,可以从系统传递给Activity的Bundle中恢复保存的状态。onCreate()与onRestoreInstanceState()回调方法都接收到了同样的Bundle,里面包含了同样的实例状态信息。

所以也可以在OnCreate()中做恢复工作

不过,因为onCreate()方法会在第一次创建新的Activity实例与重新创建之前被Destory的实例时都被调用,所以必须在尝试读取Bundle对象前检查它是否为空

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first
 
    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    ...
}