Activity的使用与理解
Activity是一个应用程序组件,它提供了一个可以和用户交互的屏幕,以便进行一些操作,比如打电话、拍照、发送电子邮件或查看地图。一个应用程序一般有一个”Main”Activity。当应用程序启动就会显示它。每个Activity都有一个窗口,用来画出它的用户界面。窗口通常会填充屏幕,但可能比屏幕小,并在其他窗口上浮动。 一个应用程序中可以包括多个Activity,他们可以通过Intent之间进行相互的启动和传递数据。
当一个Activity启动时,老的Activity就会被stop并放入到系统的一个后进先出的堆栈中,新启动的Activity就会进到栈顶并获得和用户交互的焦点,然而,当用户点击back按钮时,当前交互的Activity就会被销毁,并且堆栈中先前的Activity将会被resume并获得与用户交互的焦点。
创建一个Activity 示例代码:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 显示启动
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
// 隐式启动
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
}
}
<activity android:name=".ExampleActivity"/> // 显示启动
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"> // 隐式启动
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
创建一个有结果返回的Activity示例代码:
private void pickContact() {
// Create an intent to "pick" a contact, as defined by the content provider URI
Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
startActivityForResult(intent, PICK_CONTACT_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// If the request went well (OK) and the request was PICK_CONTACT_REQUEST
if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
// Perform a query to the contact's content provider for the contact's name
Cursor cursor = getContentResolver().query(data.getData(),
new String[] {Contacts.DISPLAY_NAME}, null, null, null);
if (cursor.moveToFirst()) { // True if the cursor is not empty
int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
String name = cursor.getString(columnIndex);
// Do something with the selected contact's name...
}
}
}
在使用startActvitiyForResult()方法启动Activity时,被启动的Activity可以调用setResult()方法返回结果到onActivityResult()方法上,同时,Activity被finish时结果才会返回。
可以使用finish()销毁Activity,或者在onActivityResult()方法中采用finishActivity()关闭startActivityForResult方法启动的Activity。
Activity在大多数情况下,您不应该使用这些方法显式地完成一个Activity。正如下面一节关于Activity生命周期的讨论,Android系统为您管理一个Activity的生命周期,因此您不需要完成您自己的Activity。调用这些方法可能会对预期的用户体验产生负面影响,只有当您绝对不想让用户返回到该Activity的实例时,才应该使用这些方法。
Activity的生命周期
这些生命周期方法的实现必须在执行任何工作之前调用父类的实现,如上述示例所示。
Method | Description | Next | |
onCeate() | 在第一次创建Activity时调用,这是您应该执行所有常规静态设置的地方—创建视图,将数据绑定到列表,等等。该方法的参数是一个包含活动前状态的Bundle对象,如果Activity销毁前的状态被保存,就可以在这里获得。 | No | onStart() |
onRestart() | 这个Activity已经停止,就在它再次被重新启动之前调用。 | No | onStart() |
onStart() | 在Activity可见之前调用。 | No | onResume() |
onResume() | 在Activity开始与用户交互之前调用,此时,Activity处于Activity堆栈的顶部。 | No | onPause() |
onPause() | 当系统即将开始恢复另一时,调用它。这种方法通常用于将未保存的更改提交到持久数据、停止动画和其他可能会消耗CPU的事情上,等等。 | Yes | onStop()或onResume() |
onStop() | 当Activity对用户不可见时,调用它。这可能是因为它正在被destroy,或者因为另一个活动(一个已经存在的或者一个新的)已经被恢复并且正在覆盖它。 | Yes | onDestroy或onRestart() |
onDestroy() | 在Activity被Destroy之前这是Activity接收到的最后一个调用,可以通过调用finish方法或者系统需要回收空间的时候销毁Activity。可以通用isFinish()方法判断是这两种销毁类型的哪一种。 | Yes | noting |
Activity的生命周期管理:
在上述表中,onPause()、onStop以及onDestroy的Killable after是Yes,表示在调用完该方法后,系统可以在紧急情况下回收内存并杀死Activity。而onPause方法是这三个回调函数的第一个,所以在onPause方法中要把一些持久化的数据进行保存,不然,后续的onStop和onDestroy方法可能不会被调用。
一个Activity在onPause调用之后到onResume方法调用之前是可以被杀的,但是当Activity正在进行交互,那必须在onPause方法之后才可以被系统回收。
根据表1中定义,不能被“杀死”的Activity可能仍然会被系统杀死,但是只有在极端情况下,当没有其他资源时,才会发生这种行为。
Activity生命周期回调顺序是很好定义的,特别是当两个Activity在同一个进程中,一个开启另一个。 以下是Acivity A启动AcivityB时发生的操作顺序:
1、Activity A's onPause();
2、Activity B's onCreate(), onStart(), andonResume()依次执行;
3、如果Activity A在屏幕上不再可见,那么它的onStop()方法就会执行。
保存Activity运行状态
在管理Activity生命周期的简介中,简要地提到,当一个Activity被暂停或停止时,Activity的状态将被保留。这是正确的,因为Activity对象在被暂停或停止时仍然保存在内存中——关于其成员和当前状态的所有信息仍然存在。因此,用户在Activity中所做的任何更改都被保留,以便当Activity返回到前台时(当它“恢复”)时,这些更改仍然存在。但是,当系统为了恢复内存而销毁Activity时,Activity对象被销毁,所以系统不能简单地恢复它的状态。 相反,如果用户导航到该对象,系统必须重新创建Activity对象。 然而,用户不知道系统销毁了Activity并重新创建了它,因此,可能期望Activity是完全一样的。 在这种情况下,您可以通过实现一个额外的回调方法来确保有关Activity状态的重要信息,从而可以保存有关Activity状态的信息:onSaveInstanceState()。
1、在Activity被销毁之前,系统调用onSaveInstanceState()。 系统将此方法传递给一个Bundle,您可以使用putString()和putInt()等方法,将关于Activity的状态信息作为键-值对保存。 然后,如果系统杀死您的应用进程,并且用户导航回您的Activity,则系统将重新创建该Activity,并将Bundle传递给onCreate()和onRestoreInstanceState()。 使用这些方法之一,您可以从Bundle中提取保存的状态并恢复Activity状态。 如果没有要恢复的状态信息,则传递给您的Bundle为null(这是首次创建Activity时的情况)。
2、onSaveInstanceState()不是每次都会执行,当用户点击back按钮的时候就不会保存。这是因为用户主动退出销毁Activity的,当onSaveInstanceState()被调用时,它一般在onStop()方法之前被调用,也有可能在onPause()方法之前被调用。
3、onSaveInstanceState()在重写时一定要调用父类的该方法,即使没有重写该方法,默认的该方法也会把一些View控件,比如:编辑框中的内容和选择框的选择项进行保存。但是这个需要你为每个控件在布局文件定义的时候给它们指定一个android:id。这样Activity在重新创建的时候就会自动恢复这些控件的内容。
4、但是由于onSaveInstanceState()不一定会被调用,因此你只能在此方法中保存短暂存在的数据。可以在onPause()方法中,把一些持久化的数据保存到数据库中。
5、onSaveInstanceState()的默认实现保存了关于Activity UI的有用信息,但是仍然需要覆盖它以保存额外的信息。例如,您可能需要保存在Activity生命期间更改的成员值(这可能与UI中恢复的值相关联,但是保留那些UI值的成员在默认情况下不会恢复)。比如,通过setSaveEnabled()方法修改的enable属性。
6、在一些配置信息改变的时,比如屏幕横竖切换,键盘可用性和语言的切换都会导致Activity销毁并重新创建,这样的话就需要对Activity状态进行保存,给用户带来更好的体验。