Activity

Activity

Activity是Android应用程序的基本组件之一,提供显示界面并处理与用户的交互。应用程序的各种空间(如EditText等)是放置在Activity之上的。Activity启动后通常占据整个显示屏幕,将用户的触摸屏事件或者按键事件分发给相应的控件进行处理。

一个应用程序通常会有多个Activity,应用程序的界面切换就是Activity的切换。切换到新的Activity后,新的Activity在屏幕上显示出来,前一个Activity隐藏起来并停止运行,系统将这个Activity的相关信息保存在Activity栈中。当用户点击Back按键时,当前的Activity被销毁,栈顶的Activity将重新开始运行。这样就实现了同一个应用程序中,不同的用户界面的切换。

创建Activity的步骤

1)  定义一个类并继承Activity或者Activity的子类

2)  为Activity创建一个界面布局(Layout)

3)  在AndroidManifest.xml文件声明Activity

4)  为Activity定义intent-filter(可选的)

创建界面布局

Android为界面开发定义了两类对象:布局(Layout)和控件(Widget)。布局是容器,用来存放多个控件或布局并以一定的规格排列控件或布局。控件是一些界面元素,比如EditText,CheckBox,Button等;布局对象有LinearLayout,GridLayout等。

启动Activity

启动一个Activity的方式有几种,可以根据实际的开发需要选择。启动Activity需要调用startActivity(Intent)方法,并传入Intent对象,需要启动的Activity由Intent对象指定。

1)  精确启动指定的Activity

在开发应用程序中,启动一个已知的Activity,这个Activity一般就是自己开发的。构造Intent时传入指定的Activity的class。下面的例子中明确指定要启动SignInActivity。

1 Intent intent = new Intent(this, SignInActivity.class);
2 startActivity(intent);

2)  模糊启动Activity

构造Intent时传入动作(Action),由系统查找可以执行此动作的Activity,并启动Activity。如果找到多个Activity,系统会弹出选择框,由用户选择启动哪一个Activity。下面的例子中设置发送动作(Intent.ACTION_SEND),调用startActivity()启动Activity。Intent.EXTRA_MAIL用来设置发送邮箱地址。

1 Intent intent = new Intent(Intent.ACTION_SEND);
2
3 intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
4
5 startActivity(intent);

获得Activity的执行结果

如果想要获得Activity的执行结果,需要调用startActivityForResult()来启动Activity,第二个参数设置请求码。当Activity执行完成,结果封装在Intent中传入你所定义的onActivityResult()回调函数中。

protected void onActivityResult (int requestCode, int resultCode, Intent data)

onActivityResult定义在Activity中,第一个参数requestCode跟startActivityForResult()的第二个参数一致,根据requestCode的值,从data提取Activity的执行结果。

 1 private void pickContact() {
2
3 // Create an intent to "pick" a contact, as defined by the content provider URI
4
5 Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
6
7 startActivityForResult(intent, PICK_CONTACT_REQUEST);
8
9 }
10
11
12
13 @Override
14
15 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
16
17 // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
18
19 if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
20
21 // Perform a query to the contact's content provider for the contact's name
22
23 Cursor cursor = getContentResolver().query(data.getData(),
24
25 new String[] {Contacts.DISPLAY_NAME}, null, null, null);
26
27 if (cursor.moveToFirst()) { // True if the cursor is not empty
28
29 int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
30
31 String name = cursor.getString(columnIndex);
32
33 // Do something with the selected contact's name...
34
35 }
36
37 }
38
39 }

终止Activity

Activity启动后,Activity的生命周期由系统管理,一般情况下,你需要关注什么时候去终止一个Activity,除非你觉得非常有必要。

终止Activity的方法是自身调用finish()方法或者由其他组件调用finishActivity()终止。

Activity的生命周期

Activity的数据保存

Activity启动后,由系统管理其生命周期。当系统内存不足时,可能会杀掉在后台运行的Activity,为了防止正在运行的Activity数据丢失,Activity提供了几个回调函数(如onPause(), onSaveInstanceState(Bundle)等),在系统杀掉Activity前,回调函数会被调用,因此,我们需要在这些回调函数中执行必要的操作保存数据,防止丢失。

Activity的数据可以划分为两类:实时数据和持久数据。实时数据是跟界面相关的数据,数据存在于内存中,例如EditText控件中的用户输入数据。持久数据是需要保存在SDCard或者手机flash上的。例如用户改写的一条数据库记录或者xml文件。根据Android的设计理念,实时数据在onSaveInstanceState(Bundle)保存,持久数据在onPause()保存。

onSaveInstanceState(Bundle)的默认实现会保存Activity中控件的状态(前提条件是控件有android:id属性,否则控件状态数据不会保存,所以你需要在Layout XML文件中为控件设置android:id属性)。一般情况下,你不需要重写onSaveInstanceState(),因此系统已经为你完成了必要的工作。如果你认为Activity有成员变量跟UI状态有关,你需要重写onSaveInstanceState(Bundle),同时,为了保证控件状态能够正确保存,在添加你的代码前,需要先调用父类的onSaveInstanceState(Bundle)方法。

1 protected void onSaveInstanceState (Bundle outstate)
2 {
3 super.onSaveInstanceState(outstate);
4
5 // do your work
6
7 }

onPause()用来保存持久数据,在Activity销毁前肯定会被调用。你也许会想,Android为什么要设计两个方法分别保存实时数据和持久数据。是否可以由一个方式完成这两件事情?例如:是否可以让onSaveInstanceState(Bundle)保存持久数据?答案是不行。因为onSaveInstanceState(Bundle)不是每次在Activity销毁前都被调用,使用onSaveInstanceState(Bundle)会造成数据丢失。当用户按下Back按键退出当前的Activity时,onSaveInstanceState(Bundle)不会调用,而onPause()会被调用。那是否可以让onPause()同时保存实时数据和持久数据?答案是可行的,但是不推荐这么做。一方面增加实现复杂度,另一方面Android已经提供了一种机制来保存实时数据,我们应该利用这种便利,不用重复造轮子。你也许还会问,为什么Android要同时设计两个方法,只提供onPause()不就行了?我想是让每个函数只做一件事情吧,这才是良好的设计。

什么时候需要onSaveInstanceState(Bundle)

Activity正在运行,实时数据就不会丢失,如果Activity被系统销毁,利用onPause()可以保证Activity的持久数据不会丢失。Activity已经销毁,实时数据没有存在的价值了。这就引出一个问题,什么时候有必要保存实时数据?有这样的场景,用户手机屏幕是竖屏时,启动Activity,当用户将手机横过来时,Activity需要横向显示,同时用户已经输入的数据保持原样。系统对这一过程的处理是,先销毁Activity,然后以横向显示的方式重新启动Activity,在这个切换过程中,系统调用onSaveInstanceState(Bundle)保存实时数据,在Activity重新启动时,调用onRestoreInstanceState(Bundle)恢复已经保存起来的实时数据。这样给用户的感觉就是Activity很顺畅的从竖向显示切换到横向显示。

onSaveInstance(Bundle)与onPause()的区别

 

onSaveInstanceState(Bundle)

onPause()

保存的数据

实时数据(UI状态等)

持久数据(数据库,xml等)

按Back按键退出Activity

不调用

调用

Activity从竖向切换到横向

调用

调用

Activity之间的协作

Activity A启动Activity B,Activity A将暂停运行,Activity B会被创建并开始运行。Activity A和Activity B各个回调函数的调用顺序:

1)  Activity A 的onPause()执行

2)  Activity B的onCreate(),onStart(),onResume()顺序执行

3)  Activity A不在屏幕显示,onStop()执行

从以上的调用步骤来看,比较微妙的地方是Activity A 的onStop()方法是在Activity B创建并在屏幕上显示完成后才被调用。

原文地址:https://www.cnblogs.com/tonyhan/p/2402991.html