您的位置:首页 > 其它

学习整理——从安卓源码上看Activity

2016-04-27 13:45 375 查看
       安卓开发的四大组件是Activity, service, broadcast receiver, 和content provider。作为业余的开发者,可能不需要太深入理解这些组件的内部实现,以及运行机制。但是如果想要在这方面有所进阶的话,这些实现的源码还是要啃的。本文将从官方源码上讲一下对Activity的理解。

概述

定义

官方对Activity的开头描述为:

/**
An activity is a single, focused thing that the user can do.
Almost all activities interact with the user,
so the Activity class takes care of creating a window for you in which you can place your UI with setContentView(int).
While activities are often presented to the user as full-screen windows,
they can also be used in other ways: as floating windows (via a theme with android.R.attr set)
or embedded inside of another activity (using ActivityGroup).
There are two methods almost all subclasses of Activity will implement:
onCreate(android.os.Bundle) is where you initialize your activity.
Most importantly, here you will usually call setContentView(int) with a layout resource defining your UI,
and using findViewById(int) to retrieve the widgets in that UI that you need to interact with programmatically.

onPause() is where you deal with the user leaving your activity.
Most importantly, any changes made by the user should at this point be
committed (usually to the android.content.ContentProvider holding the data).
**/

从安卓四大组件来看,Activity是唯一的可以与用户进行交互的组件,所以activity可以创建一个窗口并通过调用setContentView(int)来设定窗口的UI。

而且,Activity的表现形式不限于占据整个屏幕,还可以是一个悬浮窗口或者被嵌入到其他的Activity中。

Activity状态

接着再来看一个Acitivity的生命周期,虽然网上有很多对Activity生命周期的解释,但还是贴上源码上的注释:

/**
Activities in the system are managed as an activity stack. When a new activity is started,
it is placed on the top of the stack and becomes the running activity -- the previous activity
always remains below it in the stack, and will not come to the foreground again until the new activity exits.

An activity has essentially four states:
1.If an activity in the foreground of the screen (at the top of the stack), it is active or running.
2.If an activity has lost focus but is still visible (that is, a new non-full-sized or transparent activity
 has focus on top of your activity), it is paused. A paused activity is completely alive
(it maintains all state and member information and remains attached to the window manager),
but can be killed by the system in extreme low memory situations.
3.If an activity is completely obscured by another activity, it is stopped.
It still retains all state and member information, however,
it is no longer visible to the user so its window is hidden and it will often be killed by the system
when memory is needed elsewhere.
4.If an activity is paused or stopped, the system can drop the activity from memory by either asking it to finish,
or simply killing its process. When it is displayed again to the user,
it must be completely restarted and restored to its previous state.
**/
从解释中可以知道,系统是以stack的形式来管理Activity,当一个新的Activity开始时,它将处于该stack的顶部(栈顶)并成为running activity。

一个Activity的有四种状态,分别是:

1.Active或者running,当Activity处在前台,即屏幕的最前面时。

2.Paused,当Activity失去焦点但依然可见时,典型的情况是有个警告框弹出到屏幕的最前面。在这个状态下,Activity失去焦点不可接受用户的交互。当系统极端缺乏内存时,该Activity依然有可能被系统杀死。

3.Stopped,当Activity完全不可见后。

4.killed或者恢复,一个Activity处在paused或者stopped状态下,系统可以选择回收这个Activity的内存,进而杀死该Activity,或者在系统回收之前,用户重新将该Activity带到前台,进而恢复了它。要注意,系统的这种选择不受人为干预,所以开发要时刻注意Activity被杀死的情况。

生命周期类型

注释上还将Activity的生命周期按照特征分成了几种类型:

/**

1.The entire lifetime of an activity happens between the first call to onCreate(android.os.Bundle) through
to a single final call to onDestroy(). An activity will do all setup of "global" state in onCreate(),
and release all remaining resources in onDestroy().
For example, if it has a thread running in the background to download data from the network,
it may create that thread in onCreate() and then stop the thread in onDestroy().
2.The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop().
During this time the user can see the activity on-screen, though it may not be in the foreground and interacting
with the user. Between these two methods you can maintain resources that are needed to show the activity to the user.
For example, you can register a android.content.BroadcastReceiver in onStart() to monitor for changes that
impact your UI, and unregister it in onStop() when the user no longer sees what you are displaying.
The onStart() and onStop() methods can be called multiple times, as the activity becomes visible and hidden to the user.
3.The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause().
During this time the activity is in front of all other activities and interacting with the user.
An activity can frequently go between the resumed and paused states -- for example when the device goes to sleep,
when an activity result is delivered, when a new intent is delivered --
so the code in these methods should be fairly lightweight.
**/

1.完整生命周期(entire lifetime),从一个Activity被创建分配内存到内存被系统回收。

2.可视生命周期(visible lifetime),成对出现的onStart()与onStop()之间的时间,能够为用户所见。

3.前台生命周期(foregroud lifetime),成对出现的onResume()与onPause()之间的时间,能够为用户所见并交互

通过上面的解释,不难得出网上随处可见Activity生命周期图表。



看着生命周期图,对照着官方注释,来看各个回调函数的源码

回调函数

onCreate

/**
Called when the activity is starting.
This is where most initialization should go: calling setContentView(int) to inflate the activity's UI,
using findViewById(int) to programmatically interact with widgets in the UI,
calling managedQuery(android.net.Uri,java.lang.String[],java.lang.String,java.lang.String[],java.lang.String) to
retrieve cursors for data being displayed, etc.
You can call finish() from within this function,
in which case onDestroy() will be immediately called without any of the rest of the activity
lifecycle (onStart(), onResume(), onPause(), etc) executing.

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.

Parameters:
savedInstanceState If the activity is being re-initialized after previously
being shut down then this Bundle contains the data it most recently supplied in onSaveInstanceState(android.os.Bundle).
Note: Otherwise it is null.

**/
protected void onCreate(@Nullable Bundle savedInstanceState) {

if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);

if (mLastNonConfigurationInstances != null) {

mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
}
if (mActivityInfo.parentActivityName != null) {
if (mActionBar == null) {
mEnableDefaultActionBarUp = true;
} else {
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
}
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
}
mFragments.dispatchCreate();
getApplication().dispatchActivityCreated(this, savedInstanceState);
if (mVoiceInteractor != null) {
mVoiceInteractor.attachActivity(this);
}
mCalled = true;
}
当一个Activity被创建的时候,系统将回调该activity的onCreate()方法,但分清楚该方法并不是创建一个Activity。从源码上看,系统调用该方法,主要做了一些关于Activity的状态变量的修改。为了保存系统管理Acitivity的一致性,开发者重写该方法时,要求调用该父类方法。当一个Activity实例被创建后,系统只会仅此一次地调用该方法,所以该方法里适合做一些create views, bind data to lists等等的工作。要注意该方法的可空Bundle类参数savedInstanceState,只有在系统配置被修改后,系统需要快速杀死Activity并重新创建以适应系统环境时,系统才会自动加入该参数调用,里面保存的是Activity被销毁前的用户交互情况。典型的情况的设备设置了横屏,如果用户在一个输入框输入了一些字符,然后发生转屏事件,由于当前Activity是在竖屏时建立的,它并不适合横屏,所以系统需要将当前Activity销毁并重新按照横屏标准创建一个新的Activity。但由于考虑用户输入情况,系统不应该将用户在转屏前的输入状态在销毁——重建的过程中丢失掉,所以系统在销毁Activity前将信息传入该bundle,再在重建时加入该bundle以还原输入状态。

onStart

/**
Called after onCreate(android.os.Bundle) — or after onRestart() when the activity had been stopped,
but is now again being displayed to the user. It will be followed by onResume().

Derived classes must call through to the super class's implementation of this method.
If they do not, an exception will be thrown.
**/

protected void onStart() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
mCalled = true;
if (!mLoadersStarted) {

mLoadersStarted = true;
if (mLoaderManager != null) {
mLoaderManager.doStart();
} else if (!mCheckedForLoaderManager) {
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
}
mCheckedForLoaderManager = true;
}
getApplication().dispatchActivityStarted(this);
}
当Activity展现在前台时,换句话说,系统在渲染好UI之后,将调用该方法。内部实现的是一些状态变量的修改,调用更底层的函数。

onResume

/**
Called after onRestoreInstanceState(android.os.Bundle), onRestart(), or onPause(),
for your activity to start interacting with the user.
This is a good place to begin animations, open exclusive-access devices (such as the camera), etc.

Keep in mind that onResume is not the best indicator that your activity is visible to the user;
a system window such as the keyguard may be in front.
Use onWindowFocusChanged(boolean) to know for certain that your activity is visible to the user (for example, to resume a game).

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/

protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
mActivityTransitionState.onResume();
mCalled = true;
}
当Activity可以开始与用户进行交互时,系统将调用该方法。它与onStart()的调用时机不用在于,UI渲染完后还没绑定监听函数,所以用户是不可交互的,这时调用onStart()。在屏幕各个位置上绑定完监听监听函数后,即用户点击屏幕将可以得到交互时,系统调用onResume()函数。这就解释了为什么一个警告框在Activity上悬浮或消失时,Activity的生命周期只处于onPause()和onResume(),因为悬浮下的Activity是可见的,它只是失去了屏幕与监听函数的绑定,所以当警告框消失后UI不需要重新绘制,只需要能够让屏幕与监听函数重新绑定即可,故onStart()就没有被调用。而如果Activity退出前台后,它在重返前台前需要经过UI的绘制渲染,所以此时会调用onStart()。

onPause

/**
Called as part of the activity lifecycle when an activity is going into the background,
but has not (yet) been killed. The counterpart to onResume().

When activity B is launched in front of activity A, this callback will be invoked on A.
B will not be created until A's onPause() returns, so be sure to not do anything lengthy here.

This callback is mostly used for saving any persistent state the activity is editing,
to present a "edit in place" model to the user and making sure nothing is lost
if there are not enough resources to start the new activity without first killing this one.
This is also a good place to do things like stop animations and other things that consume a noticeable
amount of CPU in order to make the switch to the next activity as fast as possible,
or to close resources that are exclusive access such as the camera.

In situations where the system needs more memory it may kill paused processes to reclaim resources.
Because of this, you should be sure that all of your state is saved by the time you return from this function.
In general onSaveInstanceState(android.os.Bundle) is used to save per-instance state in the activity and this method
is used to store global persistent data (in content providers, files, etc.)

After receiving this call you will usually receive a following call to onStop()
 (after the next activity has been resumed and displayed),
however in some cases there will be a direct call back to onResume() without going through the stopped state.

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/
protected void onPause() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
getApplication().dispatchActivityPaused(this);
mCalled = true;
}
当一个Activity离开前台进入后台前,系统将调用该方法。要注意,Activity进入的后台(background)的意思,可以简单理解为Activity变得不可交互时。根据系统的定义,一个Activity在系统调用onPause()后随时有可能被killed掉,所以任何需要保存的状态、信息需要在这个函数里保存。不应该在onPause()做耗时的操作,因为onPause()完后之前,其他Activity不能够显示出来。

/**
Called when you are no longer visible to the user. You will next receive either onRestart(), onDestroy(), or nothing,
depending on later user activity.

Note that this method may never be called, in low memory situations where the system does not have
enough memory to keep your activity's process running after its onPause() method is called.

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/
protected void onStop() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
mActivityTransitionState.onStop();
getApplication().dispatchActivityStopped(this);
mTranslucentCallback = null;
mCalled = true;
}
当Activity不再可视后,系统将调用该方法。需要注意,系统需要杀死Activity来获得更多的内存时,并不会调用该方法。

onStop

/**
Called after onStop() when the current activity is being re-displayed to the user (the user has navigated back to it).
It will be followed by onStart() and then onResume().

For activities that are using raw android.database.Cursor objects
(instead of creating them through managedQuery(android.net.Uri,java.lang.String[],java.lang.String,java.lang.String[],java.lang.String),
 this is usually the place where the cursor should be requeried (because you had deactivated it in onStop().

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/

protected void onRestart() {
mCalled = true;
}

当Activity将再次展示在前台时,系统将调用该方法。

onDestroy

/**
Perform any final cleanup before an activity is destroyed.
This can happen either because the activity is finishing (someone called finish() on it,
or because the system is temporarily destroying this instance of the activity to save space.
You can distinguish between these two scenarios with the isFinishing() method.

Note: do not count on this method being called as a place for saving data!
For example, if an activity is editing data in a content provider, those edits should be committed in either onPause()
or onSaveInstanceState(android.os.Bundle), not here.
This method is usually implemented to free resources like threads that are associated with an activity,
so that a destroyed activity does not leave such things around while the rest of its application is still running.
There are situations where the system will simply kill the activity's hosting process without calling this method
(or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/
protected void onDestroy() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
mCalled = true;
// dismiss any dialogs we are managing.

if (mManagedDialogs != null) {
final int numDialogs = mManagedDialogs.size();
for (int i = 0; i < numDialogs; i++) {
final ManagedDialog md = mManagedDialogs.valueAt(i);
if (md.mDialog.isShowing()) {
md.mDialog.dismiss();
}
}
mManagedDialogs = null;
}

// close any cursors we are managing.
synchronized (mManagedCursors) {
int numCursors = mManagedCursors.size();
for (int i = 0; i < numCursors; i++) {
ManagedCursor c = mManagedCursors.get(i);
if (c != null) {
c.mCursor.close();
}
}
mManagedCursors.clear();
}
// Close any open search dialog
if (mSearchManager != null) {
mSearchManager.stopSearch();
}
getApplication().dispatchActivityDestroyed(this);
}
当Activity调用finish()后或者系统需要销毁该Activity时,系统将调用该方法。要注意,系统依然可以选择不调用该方法而直接销毁Activity。

总结:

1.Activity生命周期的回调函数是系统在进行下一步操作前后调用的,以供开发者在各个阶段前后实现一些操作;

2.某些回调函数的父类实现比较简单,但都是打通一个Activity生命周期的重要操作。所以为了保持Activity的一致性,避免开发者不理解整一个生命周期原理,Android强制要求在重写这些回调函数时需要调用父类实现;

3.Activity的生命周期中onCreate()只会调用一次,需要适合一个全局变量的赋值,监听函数的设定,而onStart()和onResume()可能会被多次调用,所以不适合在方法里创建对象,因为调用一次,之前的对象就是成了垃圾。垃圾多了,对程序对系统都不是一件好事;

4.某些情况下,系统可以越过onStop()和onDestroy()而直接杀死Activity,所以一些重要信息的保存要放在onPause()里;

5.Activity的运作原理就是系统对各种回调函数的调用,开发者无法控制一个Activity的生命周期,但可以在其生命周期中定制一些实现,让其能够按照定义一般运行下去;

5.在Activity里可以找到很多函数,最大程序上保证了一个Activity能够实现的工程,这表示了一个系统多么精巧而缜密的。比如一个onKeyDown()回调函数,用以监测一个用户的输入情况。但按键的监测也是一个系统行为,它会按照传递等级一层一层地将输入情况向下传递,如果输入在某一层得到处理,返回true以表示让系统不再将输入情况向下传递,返回false则表示在这层没得到处理,系统可以继续向下传递。等等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: