专栏首页机器学习入门Android Activity生命周期整理

Android Activity生命周期整理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014688145/article/details/50638509

最近,开始学习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崩溃以及用户数据的丢失。

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

在上图展示的六个状态,其中三个是属于静态的,而另外三个是瞬态的(将直接跳转到下一状态。)。静态的便是:Resumed、Paused、Stopped,这三个状态能长时间存在。

  • Resumed:

在这个状态下,activity运行在前台,用户能够做任何操作。

  • Paused:

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

  • Stopped:

在这个状态下,当前activity被全部遮住,即对用户不可见,但是它还在后台俏俏的待命。当activity 停止时,当前activity实例以及状态信息,诸如成员变量等都保留在内存中,但不能执行任何用户操作。

这便是activity最基本的生命周期。接下来,将介绍每个状态对应具体的行为。

实战一发

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

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

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

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()方法中记得释放它。

@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;

}

}

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

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

正如前面代码所示,如果你在onPause方法中,释放了一些系统资源,那么一旦用户回到activity就需要相应的初始化释放掉的资源。其次,初始化之前只在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

}

}

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方法中保存这些内容:

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

values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());

values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

getContentResolver().update(

mUri, // The URI for the note to update.

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状态下,这些数据依然留存。因此,对于我们来讲,注意那些非视图组件的信息的留存即可。

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

@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中的文本信息的留存,便是最好的例证。

可惜,系统只能保存有限的信息,编写程序时,有很多用户数据是并非由系统来完成管理的。因此,如果想要保存额外的信息,需要借助onSaveInstanceState()方法来实现。

由图可以看出,在进入Destroyed之前,该方法自动执行,我们只要在这里记录一些用户信息,传给bundle即可。当下次app重启时,在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);

}

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

@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

}

...

}

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

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • LeetCode Weekly Contest 43解题思路

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

    用户1147447
  • LeetCode Weekly Contest 46解题思路

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

    用户1147447
  • LeetCode Weekly Contest 41解题思路

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

    用户1147447
  • 基于双眼视觉的高精度无人机目标定位系统(CS CV)

    在工作过程中,无人驾驶车辆常常需要高精度地定位目标。在无人材料搬运车间中,无人车辆需要对工件进行高精度的姿态估计以准确地抓住工件。在此背景下,本文提出了一种基于...

    gaowanting
  • CNCF大使档案:TiKV的Queeny Jin

    Our first ambassador spotlight goes to Queeny Jin, who has been spreading the wo...

    CNCF
  • 通用最小曼哈顿网络问题的动态编程方法(CS DS)

    我们研究广义最小曼哈顿网络(GMMN)问题:给定一个由欧几里得平面 中两个点配对组成的集合 ,要求我们找到一个最小长度的几何网络,该网络由轴对齐的线段...

    刘持诚
  • Android NDK Debug

    前言:说真的Android NDK debug还是推荐lldb,gdb经常莫名其妙的不成功。不过下面的这个流程是谷歌官方建议的,还是有参考价值的。尤其是在App...

    望天
  • Convolution_model_Application_v1a

    Welcome to Course 4's second assignment! In this notebook, you will:

    列夫托尔斯昊
  • Duke@coursera 数据分析与统计推断 unit1 part2 introduction to data

    roughly the average deviation around themean, and has the same units as the data

    统计学家
  • Taking a more fundamental approach to regularization with LARS

    To borrow from Gilbert Strang's evaluation of the Gaussian elimination, LARS is ...

    到不了的都叫做远方

扫码关注云+社区

领取腾讯云代金券