Android的Activity组件

胸怀万里世界, 放眼无限未来。这篇文章主要讲述Android的Activity组件相关的知识,希望能为你提供帮助。
本章主题是Activity组件;Activity是android四大组价之一,其重要地位自然不用说。“Activity是应用程序中可见的交互组件的基类,大致上等同于传统桌面应用个程序开发中的窗体。”(引自---《Android 4 高级编程》)。如果想要在界面上展示布局及相关内容,肯定是需要有Activity实例的。
总结(根据思考的问题,得到结论):
1. 在Activity生命周期的各个回调方法中该执行什么操作?(弄清楚回调的特征)
a) Activity的onCreate()只会执行一次,含义就是创建Activity;

b) 与onPause()对应的onResume(),可执行相反的初始化逻辑。一定要让onPause()和onResume中的代码执行迅速,并且其中的代码应该尽可能少,以保证在前台和后台之间进行切换的时候应用程序能够保持响应。

c) onPause()中应该去停止动画的执行或者其他消耗CPU的操作;提交未保存的状态;释放系统资源,比如:广播接受者,对硬件的监听或者其他损耗电池的操作。避免在其中执行:负担较重的CPU计算操作,比如数据库写入等(以保证Activity切换的流畅性)

d) onStop()中可执行较重的CPU计算操作,比如数据库写入等,还应该用来暂停或停止动画、线程、传感器监听器、GPS查找、定时器、Service或者其他专门用户更新用户界面的进程;此外,如果系统内存吃紧时,系统可能不会执行onDestory(),而将Activity实例销毁,所以必须在onStop()中释放有可能会导致内存溢出的实例。

e) 执行onDestory()意味着系统将会销毁其Activity的内存空间,其实例也就销毁了;onDestory()的执行是最后一次机会去销毁可能引发内存溢出以及销毁工作线程的时机;在以下几种情况下,会执行onDestory():执行Back按键逻辑,或者finish();如果Activity在Stopped状态,且存在很长时间未被调回到前台运行,或者是系统内存吃紧时,都将会执行onDestory()。这个时候就需要保存Activity的状态信息,涉及到onSaveInstanceState()和onRestoreInstanceState()的执行。

每一个Activity都表示一个屏幕,应用程序会把它呈现给用户。应用程序越复杂,需要的屏幕可能就越多。典型情况下,这至少包括一个用来处理应用程序的主UI功能的主界面屏幕(MainActivity,或者是在AndroidManifest.xml文件中包含有:.action.MAIN和.category.LAUNCHER的intent-filter属性的Activity)。这个主界面一把由许多Fragment组成,或者通常由一组次要Activity支持。要在屏幕之间进行切换,就必须要启动一个新的Activity(或者从一个Activity返回)。
基本Activity类出现了一个封装了窗口显示处理功能的空白屏幕。一个空Activity并不是特别有用,应该使用Fragment、布局(指的是各种Layout:LinearLayout、RelativeLayout等等)和视图(指的是View实例)来创建UI。
布局和视图的区别是什么?
上述提到了创建UI(User Interface)的三种方式:
1. Fragment:用来封装UI的各个部分。
2. 布局:Android提供了多个布局类,统称为ViewGroup(是否可以称为是Layout?),可以包含多个视图来帮助布局UI。
3. 视图:可以用View表示,用来显示数据和提供用户交互的UI控件。
【Android的Activity组件】对于一个空白的Activity实例,将View填充到该Activity中:

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LogUtil.d(TAG, "onCreate.."); DemoApplication instance = DemoApplication.getInstance(); if (null != instance) { LogUtil.d(TAG, "instance is not null..."); } TextView textView = new TextView(this); textView.setText("MainActivity demo ...."); setContentView(textView); }

使用setContentView()填充到给Activity中...
As a user navigates through, out of, and back to your app, the Activity instances in your app transition between different states in their lifecycle. 
For instance, when your activity starts for the first time, it comes to the foreground of the system and receives user focus. During this process, the Android system calls a series of lifecycle methods on the activity in which you set up the user interface and other components. For example, if you\'re building a streaming video player, you might pause the video and terminate the network connection when the user switches to another app. When the user returns, you can reconnect to the network and allow the user to resume the video from the same spot.
Android的Activity组件

文章图片

P.S. “partially obscured”部分阻塞;
Unlike other programming paradigms in which apps are launched with a main() method, the Android system initiates code in an Activity instance by invoking specific callback methods that correspond to specific stages of its lifecycle. Android程序的入口不是从main()开始,而是从Activity的生命周期回调方法开始的。
Activity生命周期如下:
Android的Activity组件

文章图片

As the system creates a new activity instance, each callback method moves the activity state one step toward the top. The top of the pyramid is the point at which the activity is running in the foreground and the user can interact with it.
Implementing your activity lifecycle methods properly ensures your app behaves well in several ways, including that it(最佳实践效果,也就是在自定义Activity中必须要保证的条件):
1. Does not crash if the user receives a phone call or switches to another app while using your app.(跳转至其他app,或者是来电状态不会导致奔溃)
2. Does not consume valuable system resources when the user is not actively using it. (不在本app时,不会损耗系统资源,比如:网络等)

3. Does not lose the user\'s progress if they leave your app and return to it at a later time. (离开本app,并在返回时必须保存用户状态)

4. Does not crash or lose the user\'s progress when the screen rotates between landscape and portrait orientation. (屏幕转换时,不会奔溃或者丢失用户状态)

However, only three of these states can be static. That is, the activity can exist in one of only three states for an extended period of time.
Resumed --- In this state, the activity is in the foreground and the user can interact with it. (Also sometimes referred to as the "running" state.)

Paused --- In this state, the activity is partially obscured by another activity—the other activity that\'s in the foreground is semi-transparent or doesn\'t cover the entire screen. The paused activity does not receive user input and cannot execute any code.
以及
Stopped --- In this state, the activity is completely hidden and not visible to the user; it is considered to be in the background. While stopped, the activity instance and all its state information such as member variables is retained, but it cannot execute any code.
The other states (Created and Started) are transient and the system quickly moves from them to the next state by calling the next lifecycle callback method. That is, after the system calls onCreate(), it quickly calls onStart(), which is quickly followed by onResume(). Once the onCreate() finishes execution, the system calls the onStart() and onResume() methods in quick succession. Your activity never resides in the Created or Started states.
上述提到了Android应用程序的入口是一个Activity,那这个入口该如何指定? Specify your app\'s Launcher Activity
< activity android:name="com.spt.activity.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>

在AndroidManifest.xml文件中,为指定的Activity添加< intent-filter> 标签,并附带有 MAIN action 和 LAUNCHER category。
If either the MAIN action or LAUNCHER category are not declared for one of your activities, then your app icon will not appear in the Home screen\'s list of apps. 如果AndroidManifest.xml中,没有声明 MAIN action 或者 LAUNCHER category ,主屏幕上将不会显示该应用程序图标。(只有当以上两者都存在时,才会显示应用程序图标)
Create a New Instance 创建一个新的Activity实例
You must implement the onCreate() method to perform basic application startup logic that should happen only once for the entire life of the activity. onCreate()在每一个Activity实例上都只执行一次。For example, your implementation of onCreate() should define the user interface and possibly instantiate some class-scope variables, such as declaring the user interface (defined in an XML layout file), defining member variables, and configuring some of the UI. 一般是在onCreate()中初始化一些全局变量。
Android的Activity组件

文章图片

Destory the Activity 销毁Activity实例
While the activity\'s first lifecycle callback is onCreate(), its very last callback is onDestroy(). The system calls this method on your activity as the final signal that your activity instance is being completely removed from the system memory.
Most apps don\'t need to implement this method because local class references are destroyed with the activity and your activity should perform most cleanup during onPause() and onStop(). However, if your activity includes background threads that you created during onCreate() or other long-running resources that could potentially leak memory if not properly closed, you should kill them during onDestroy(). 一般在onDestory()中执行:停止工作线程。

Note: The system calls onDestroy() after it has already called onPause() and onStop() in all situations except one: when you call finish() from within the onCreate() method. In some cases, such as when your activity operates as a temporary decision maker to launch another activity, you might call finish() from within onCreate() to destroy the activity. In this case, the system immediately calls onDestroy() without calling any of the other lifecycle methods.
For example, when a semi-transparent activity opens (such as one in the style of a dialog), the previous activity pauses. As long as the activity is still partially visible but currently not the activity in focus, it remains paused. 半透明的Activity覆盖了前一个Activity,前一个Activity仍然能够被看到的情况中,该Activity处在Paused状态。
However, once the activity is fully-obstructed and not visible, it stops (which is discussed in the next lesson). 界定Stopped状态。
Android的Activity组件

文章图片

执行onPause()时,意味着可能Activity是部分可见的,同时意味着用户将会离开Activity,并进入Stopped状态。
一般情况下,会在onPause()回调中执行以下动作:
  1. Stop animations or other ongoing actions that could consume CPU.
  2. Commit unsaved changes, but only if users expect such changes to be permanently saved when they leave (such as a draft email).
  3. Release system resources, such as broadcast receivers, handles to sensors (like GPS), or any resources that may affect battery life while your activity is paused and the user does not need them.
举个栗子:
@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; } }

避免在onPause()中做的事情:
However, you should avoid performing CPU-intensive work during onPause(), such as writing to a database, because it can slow the visible transition to the next activity (you should instead perform heavy-load shutdown operations during onStop()). CPU执行次数多的操作,比如写DB等,导致进入下一个Activity缓慢;应该将这些操作移到onStop()中执行。
You should keep the amount of operations done in the onPause() method relatively simple in order to allow for a speedy transition to the user\'s next destination if your activity is actually being stopped. 保持onPause()中方法的简单和快捷,以保证切换Activity的顺畅性。
进入到Paused状态时,Activity实例会常驻内存,不需要在返回到Resumed状态时初始化Activity的相关组件。
As such, you should implement onResume() to initialize components that you release during onPause() and perform any other initializations that must occur each time the activity enters the Resumed state (such as begin animations and initialize components only used while the activity has user focus). 在从Paused状态返回到Resumed状态时,会执行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 } }

onResume()和onPause()中的回调是相对的。
Android的Activity组件

文章图片

以下情况可能会导致Activity进入到Stopped状态:
1. The user opens the Recent Apps window and switches from your app to another app. The activity in your app that\'s currently in the foreground is stopped. If the user returns to your app from the Home screen launcher icon or the Recent Apps window, the activity restarts.
2. The user performs an action in your app that starts a new activity. The current activity is stopped when the second activity is created. If the user then presses the Back button, the first activity is restarted.
3. The user receives a phone call while using your app on his or her phone.
Unlike the paused state, which identifies a partial UI obstruction, the stopped state guarantees that the UI is no longer visible and the user\'s focus is in a separate activity (or an entirely separate app). Stopped状态和Paused状态在UI上的不同,后者是部分阻塞,而前者的UI是完全不可见,同时失去焦点。
需要指出的是,不论什么情况导致Activity过渡到Stopped状态,onPause()总是在onStop()之前执行。
Once your activity is stopped, the system might destroy the instance if it needs to recover system memory. In extreme cases, the system might simply kill your app process without calling the activity\'s final onDestroy() callback, so it\'s important you use onStop() to release resources that might leak memory. Although the onPause() method is called before onStop(), you should use onStop() to perform larger, more CPU intensive shut-down operations, such as writing information to a database.
@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. ); }

上述是一个实例,用于在onStop()中执行数据存储操作。
Note: Even if the system destroys your activity while it\'s stopped, it still retains the state of the View objects (such as text in an EditText) in a Bundle (a blob of key-value pairs) and restores them if the user navigates back to the same instance of the activity (the next lesson talks more about using a Bundle to save other state data in case your activity is destroyed and recreated).
若需要从Stopped状态回到Resumed状态时,The onRestart() method, however, is called only when the activity resumes from the stopped state, so you can use it to perform special restoration work that might be necessary only if the activity was previously stopped, but not destroyed. For this reason, you should usually use the onStart() callback method as the counterpart to the onStop() method, because the system calls onStart() both when it creates your activity and when it restarts the activity from the stopped state. 在onStart()中执行与onStop()相对的逻辑。
@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 }

一旦系统Destory Activity时,onDestory() --> This method is your last chance to clean out resources that could lead to a memory leak, so you should be sure that additional threads are destroyed and other long-running actions like method tracing are also stopped.
很多情况下需要重建Activity(也就是在系统销毁了Activity后才需要重建该Activity)。
There are a few scenarios in which your activity is destroyed due to normal app behavior, such as when the user presses the Back button or your activity signals its own destruction by calling finish(). The system may also destroy your activity if it\'s currently stopped and hasn\'t been used in a long time or the foreground activity requires more resources so the system must shut down background processes to recover memory. 
系统会在销毁Activity时,将数据保存到Bundle对象中。(However, if the system destroys the activity due to system constraints (rather than normal app behavior), then although the actual Activity instance is gone, the system remembers that it existed such that if the user navigates back to it, the system creates a new instance of the activity using a set of saved data that describes the state of the activity when it was destroyed. The saved data that the system uses to restore the previous state is called the "instance state" and is a collection of key-value pairs stored in a Bundle object.)
Caution: Your activity will be destroyed and recreated each time the user rotates the screen. When the screen changes orientation, the system destroys and recreates the foreground activity because the screen configuration has changed and your activity might need to load alternative resources (such as the layout). 需要注意到是: Activity在切换屏幕方向时,会重新执行Activity的生命周期。
Android的Activity组件

文章图片

为了存储更多的状态数据,需要覆写onSaveInstanceState()。获取到的Bundle数据会传递到onCreate()和onRestoreInstanceState()中。
保存状态信息:
The default implementation of this method saves information about the state of the activity\'s view hierarchy, such as the text in an EditText widget or the scroll position of a ListView. To save additional state information for your activity, you must implement onSaveInstanceState() and add key-value pairs to the Bundle object. 
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); }

Caution: Always call the superclass implementation of onSaveInstanceState() so the default implementation can save the state of the view hierarchy. 必须要调用父类的onSaveInstanceState(),这样才能保存View的视图状态信息。
恢复状态信息:
Because the onCreate() method is called whether the system is creating a new instance of your activity or recreating a previous one, you must check whether the state Bundle is null before you attempt to read it. If it is null, then the system is creating a new instance of the activity, instead of restoring a previous one that was destroyed. 此时需要判断系统是新建还是重建Activity。
@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 } ... }

Instead of restoring the state during onCreate() you may choose to implement onRestoreInstanceState(), which the system calls after the onStart() method. The system calls onRestoreInstanceState() only if there is a saved state to restore, so you do not need to check whether the Bundle is null.
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的生存期,对于保证应用程序提供一个连贯流程的用户体验以及合理地管理资源是很重要的。
Android应用程序不能控制自己进程的生存期;而运行时可以管理每个应用程序的进程,也就是可以管理其中的每个Activity。运行时是如何管理应用程序的Activity状态的?
需要引入一个新的概念:Activity栈
Android的Activity组件

文章图片

每个Activity的状态是由它在Activity栈中所处的位置决定的,Activity栈是当前所有正在运行的Activity的后进先出的集合。当Android的内存管理器决定终止哪个应用程序来释放资源时,会使用这个栈来决定应用程序的优先级。随着Activity的创建和销毁,该Activity的实例会从栈中移进移出。
上述的Activity的状态指的是什么?
Activity的状态和Activity在栈中的位置是相关的。
可能的状态有以下几种:
1. 活动状态:当一个Activity位于栈顶的时候,是可见的、具有焦点的前台Activity,可以接收用户输入。
2. 暂停状态:Activity是可见的,但没有获得焦点(也就是不能接收用户输入),此时就是暂停状态。
3. 停止状态:当一个Activity不可见时,就处于停止状态。在一个Activity停止的时候,保存数据和当前的UI状态以及停止任何非关键操作是很重要的。
4. 非活动状态:当一个Activity被终止之后,在启动之前就会处于非活动状态。处于非活动状态的Activity已经从栈中移除,也就是在重新被显示和使用之前,需要被重新创建。
Activity从暂停、停止或者非活动状态转化为活动状态时,用户应该感觉不到任何区别。因此,当一个Activity被暂停或停止时,保存所有的UI状态并保存所有的数据是很重要的操作。一旦一个Activity变为活动状态,就应该恢复那些被保存的值。
Android运行时会改变Activity的状态,但软件开发人员需要知道各状态,如何监听状态改变?
为了保证Activity可以对状态改变做出反应,Android提供了一系列事件处理程序(回调方法),当Activity在完整的、可见的和活动的生存期之间转化时,就会触发调用这些方法。
Android的Activity组件

文章图片

onStop()方法应该用来暂停或停止动画、线程、传感器监听器、GPS查找、定时器、Service或者其他专门用户更新用户界面的进程。当UI不可见时更新UI是没有意义的,因为这样消耗了资源(如CPU周期或者网络带宽)却没有起到实际的作用。
onStart()或者onStop()也可以用来注册和注销那些专门用来更新用户界面的Broadcast Receiver。
一定要让onPause()和onResume中的代码执行迅速,并且其中的代码应该尽可能少,以保证在前台和后台之间进行切换的时候应用程序能够保持响应。
实例展示如下:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LogUtil.d(TAG, "onCreate.."); TextView textView = new TextView(this); textView.setText("MainActivity demo ...."); setContentView(textView); } @Override protected void onRestart() { super.onRestart(); LogUtil.d(TAG, "onRestart"); } @Override protected void onStart() { super.onStart(); LogUtil.d(TAG, "onStart"); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { // 从savedInstanceState中恢复UI状态 // 自Activity上次可见之后,只有当系统终止该Activity时,才会被调用 super.onRestoreInstanceState(savedInstanceState); LogUtil.d(TAG, "onRestoreInstanceState"); } @Override protected void onResume() { super.onResume(); LogUtil.d(TAG, "onResume"); } @Override protected void onPause() { // 活动状态结束时调用 // 可以做的事情:挂起不需要更新的UI更新、线程或者CPU密集的进程 super.onPause(); LogUtil.d(TAG, "onPause"); } @Override protected void onSaveInstanceState(Bundle outState) { // 保存Activity状态和数据 // 如果进程被运行时终止并被重启,outState会被传递到onCreate()和onRestoreInstanceState()中 super.onSaveInstanceState(outState); LogUtil.d(TAG, "onSaveInstanceState"); } @Override protected void onStop() { // 在可见生存期结束时调用 super.onStop(); // 可以做的事情:挂起不需要的UI更新、线程或处理 // 必需做的事情:保存所有的编辑或者状态改变(进程可能被终止) LogUtil.d(TAG, "onStop"); } @Override protected void onDestroy() { // 清理所有资源,包括:结束线程、广播数据库连接 super.onDestroy(); LogUtil.d(TAG, "onDestroy"); }

此外,Android SDK包含了一些Activity子类来封装对常用的用户界面Widget的使用。比如:
MapActivity,在一个Activity中封装了支持Map View Widget所要求的资源处理;
ListActivity,将一个ListView绑定到了一个数据源,从而作为主UI元素,提供列表项选择的事件处理程序。

    推荐阅读