前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Activity生命周期整理

Android Activity生命周期整理

作者头像
用户1147447
发布2019-05-26 10:02:05
8210
发布2019-05-26 10:02:05
举报
文章被收录于专栏:机器学习入门

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1434864

最近,开始学习android官网提供的training 官方文档。比起一般学习教材,官网上的内容,给我最大的感受是,这更像是软件设计的艺术。它不仅仅讲每个知识点具体应该如何做,能达到效果,另外一点非常重要的内容是:对应每个知识点,我们需要注意什么,这里为什么不能写具体的coding,在那就能写了。废话不多说,开始翻译、记录、学习。

理解activity生命周期函数

这是Android启动应用时,activity将要走过的路线。和之前我学到的Activity图有所出路。

这两张图都描述了activity的行走路线,我个人更喜欢第一张图。第一张图的描述,类似于金字塔型。这非常形象地描述了Activity从onCreate()开始是如何一步一步走向顶端的Resumed。由图也能看出,一个activity经过onCreate()以及onStart()后,倘若activity始终处于运行状态,它将停留在Resumed状态下。接着,图片又描述了Paused状态以及Stopped状态。它们在不同的情况下,又能回到Resumed状态,最后便是金字塔的另外一端,Destroyed。这也就意味着Activity最终将释放所有资源,从内存中退出。

官方文档中在此刻提出编写APP四个要求:

  • 在用户转去接听电话时或者操作其他APP时,你的编写APP不能崩溃。(对应的是哪些状态函数需要修改呢?)
  • 当用户并没有想要使用它,不要消费系统资源。
  • 当用户短暂离开APP时,如有必要,要能够把当前用户的数据记录下来。
  • 当屏幕切换竖屏横屏时,不要导致APP崩溃以及用户数据的丢失。

用户操作手机的过程,都会相应的调用状态函数,因此,我们应该清楚这些注意点,对应的都是哪些状态函数。以及写该状态函数时,需要注意的点。

代码语言:txt
复制
 在上图展示的六个状态,其中三个是属于静态的,而另外三个是瞬态的(将直接跳转到下一状态。)。静态的便是:Resumed、Paused、Stopped,这三个状态能长时间存在。
  • Resumed:
代码语言:txt
复制
 在这个状态下,activity运行在前台,用户能够做任何操作。
  • Paused:

只有当前activity被另外一个activity部分遮住,或者另外一个activity为半透明,总之不能被全部遮住,才会跳转到这个状态下。值得注意的是:在这个状态下是不能接收用户输入操作并且不能执行任何用户操作。

  • Stopped:
代码语言:txt
复制
 在这个状态下,当前activity被全部遮住,即对用户不可见,但是它还在后台俏俏的待命。当activity 停止时,当前activity实例以及状态信息,诸如成员变量等都保留在内存中,但不能执行任何用户操作。
代码语言:txt
复制
 这便是activity最基本的生命周期。接下来,将介绍每个状态对应具体的行为。

实战一发

想了解activity创建后,所有状态是如何依次执行的,只要重写各种状态回调函数即可。这里列出最常用的onCreat()方法的构建。

代码语言:javascript
复制

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

代码语言:txt
复制
`setContentView(R.layout.main_activity);`

// Initialize member TextView so we can manipulate it later

代码语言:txt
复制
`mTextView =` `(TextView) findViewById(R.id.text_message);`

Log.d("debug","oncreate() callback......");

// 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();

代码语言:txt
复制
    `actionBar.setHomeButtonEnabled(false);`

}

}

Created状态总结:

  • onCreate方法是android程序初始化最先执行的回调方法,因此,所有的界面初始化工作,以及任何APP所需的资源初始化工作要在该方法下完成。
  • onCreate方法是瞬态的,一旦执行完所有的初始化代码,便立即执行onStart方法,onResume方法,到达Resumed状态。用户操作均在此状态下完成。

Resumed&&Paused状态总结:

当用户正常使用APP时,有时候便会发生切换视图组件,导致当前activity暂停的情况。只要当前activity的一部分视图能被用户看见,但用户的操作不聚焦在当前activity上,便会发生状态转移。

一旦activity从paused状态回到resumed状态,就会调用onResume方法。当用户调用onPause方法后,很大的概率将要导致用户离开APP,这也就暗示着会相继发生onStop方法。因此,我们通常在onPause()方法中需注意几点:

  1. 提交没有保存的数据,尤其是用户希望在离开时能够自动保存的数据。(草稿邮件等)
  2. 释放系统资源,诸如:广播,传感处理器(GPS等),或者其他任何可能影响电池寿命的系统资源且用户使用不到的。
  3. 停止动画或者其他一些消耗CPU的活动。

举个例子:当我们使用相机时,在onPause()方法中记得释放它。

代码语言:javascript
复制

@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) {

代码语言:txt
复制
    `mCamera.release();`
代码语言:txt
复制
    `mCamera =` `null;`

}

}

但一般情况下,也并非保存所有的用户数据,除非用户是希望当离开APP时,有自动保存的功能,草稿箱适合这样的情况下使用。而且,我们应该尽量避免保存数据的操作时间过程,如需要写入数据库等操作,这会影响用户切换到其他activity的用户体验。尽量将这些繁杂的操作在onStop()方法中执行。总之,在onPause()中,尽量简化代码,以获得更快的转移效果。

Note: 当activity进入paused状态后,它之前所初始化的组件信息是存储在内存中的,并不会消失,因此也无需在onResume()方法中重新进行初始化。

代码语言:txt
复制
 正如前面代码所示,如果你在onPause方法中,释放了一些系统资源,那么一旦用户回到activity就需要相应的初始化释放掉的资源。其次,初始化之前只在onResume方法中初始化的资源。
代码语言:javascript
复制

@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) {

代码语言:txt
复制
    `initializeCamera();` `// Local method to handle camera init`

}

}

Stopped&&Started状态总结:

在我们的程序中,恰当的停止以及重启我们的程序是必要的。设计软件时,需给用户一种完整的app体验。Stopped发生的场景:

  • 当用户打开最近使用的APP窗口,并且转到另外一个APP时,当前的activity将会调用onStop()方法,进入Stopped状态,当用户再次返回时,会回调onRestart()方法,重新进入started状态以及Resumed状态。
  • 当用户在当前界面启动另外一个新的activity后,当前activity将进入stopped状态,当用户按住返回按钮后,重新回调onRestart()方法。
  • 当用户使用当前app时,有电话接入,也会进入Stopped状态。

这里同样需要注意的一点是:如同进入Paused状态一样,系统还会保留当前activity实例在我们的内存中。因此,也可以不用重写onStop()和onRestart()方法。对于绝大多数简单的应用,只需要在activity进入stopped状态之前,重写onPause()方法,来关闭一些正在执行的动作,释放系统资源即可。

还需要注意一点的是:有时候系统由于内存资源使用紧张的情况下,会莫名其妙的直接kill掉你的app程序,这时候它是不会调用onDestroy()方法的,因此,在onStop中,如果APP涉及一些大资源,如数据库的读写操作的使用时,建议在onStop方法中,保存用户数据并关掉这些资源,避免内存泄漏。

如用户在编辑内容时,onStop方法中保存这些内容:

代码语言:javascript
复制

@Override

protected void onStop() {

super.onStop(); // Always call the superclass method first

// Save the note's current draft, because the activity is stopping

// and we want to be sure the current note progress isn't lost.

ContentValues values = new ContentValues();

代码语言:txt
复制
`values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());`
代码语言:txt
复制
`values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());`
代码语言:txt
复制
`getContentResolver().update(`
代码语言:txt
复制
        `mUri,` `// The URI for the note to update.`
代码语言:txt
复制
        `values,` `// The map of column names and new values to apply to them.`

null, // No SELECT criteria are used.

null // No WHERE columns are used.

);

}

记得,在onRestart方法中,重新获得这些数据即可。但是否所有的用户数据需要保存呢?不然,视图组件的状态,系统其实会自动记录在内存中,如在editText中,编写的用户数据,完全不需要保存,当用户从stopped状态回到resumed状态后,editText里的内容由系统自动调用。甚至在destroyed状态下,这些数据依然留存。因此,对于我们来讲,注意那些非视图组件的信息的留存即可。

代码语言:txt
复制
 在官方文档中,它其实并不提倡使用onRestart方法,除非一些应用是确定不会进入destroyed状态,只会停留在stopped状态。但为了以防万一,还是建议使用onStart方法,并且在onStart方法中,要注意当前的系统环境是否支持某些初始化操作。如:
代码语言:javascript
复制

@Override

protected void onStart() {

super.onStart(); // Always call the superclass method first

// The activity is either being restarted or started for the first time

// so this is where we should make sure that GPS is enabled

LocationManager locationManager =

(LocationManager) getSystemService(Context.LOCATION_SERVICE);

boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

if (!gpsEnabled) {

// Create a dialog here that requests the user to enable GPS, and use an intent

// with the android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS action

// to take the user to the Settings screen to enable GPS when they click "OK"

}

}

@Override

protected void onRestart() {

super.onRestart(); // Always call the superclass method first

// Activity being restarted from stopped state

}

最后还需注意的一点是:在onDestroy()方法中,是最后释放所有系统资源的机会,切忌别让app内存泄漏了。o(︶︿︶)o

Destroyed状态总结:

Destroyed发生的场景:

  • 用户操作返回按钮后。
  • 在程序中调用finish方法。
  • app进入stopped状态后,用户长时间并没有唤醒app,系统清理内存时,自动关闭它。

当然,并非所有的程序APP如我们所想,能顺利结束,有很多种情况让它意外退出,因此,为了防止意外退出的发生,系统提供了一种机制来保存activity的实例,这种机制便是 通过bundle绑定“instance state”,以键值对的方式保存在bundle对象中。当程序app启动时,自动加载系统的实例状态,呈现在用户面前。前面提到的editText中的文本信息的留存,便是最好的例证。

代码语言:txt
复制
 可惜,系统只能保存有限的信息,编写程序时,有很多用户数据是并非由系统来完成管理的。因此,如果想要保存额外的信息,需要借助onSaveInstanceState()方法来实现。
代码语言:txt
复制
 由图可以看出,在进入Destroyed之前,该方法自动执行,我们只要在这里记录一些用户信息,传给bundle即可。当下次app重启时,在onCreate方法和onRestoreInstanceState方法中,都能够重新加载信息。有两个地方供我们提取出之前维护的信息,选择其中一个方法即可。

来个例子:

代码语言:javascript
复制

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

代码语言:txt
复制
`savedInstanceState.putInt(STATE_SCORE, mCurrentScore);`
代码语言:txt
复制
`savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);`

// Always call the superclass so it can save the view hierarchy state

super.onSaveInstanceState(savedInstanceState);

}

重新加载用户保存的信息:

代码语言:javascript
复制

@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

代码语言:txt
复制
    `mCurrentScore = savedInstanceState.getInt(STATE_SCORE);`
代码语言:txt
复制
    `mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);`

} else {

// Probably initialize members with default values for a new instance

}

...

}

这里需要注意的一点是:savedInstanceState判空的细节,因为程序很有可能正常退出,因此savedInstanceState,在app创建一个新的实例时,定为空。这也验证了,只有当程序意外退出时,才会调用onSaveInstanceState方法。

当然,我们也可以选择更加方便的方法,无需判空,重写onRestoreInstanceState方法即可:

代码语言:javascript
复制
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);
}

分享结束、fighting!o(∩_∩)o

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年02月05日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 理解activity生命周期函数
    • 官方文档中在此刻提出编写APP四个要求:
      • 实战一发
        • Created状态总结:
        • Resumed&&Paused状态总结:
        • Stopped&&Started状态总结:
        • Destroyed状态总结:
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档