本帖最后由 王震阳老师 于 2015-3-23 22:21 编辑
pdf附件回复可见:
1. Activity简介(★★)Activity是Android四大组件之一,它用于展示界面。Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务。Activity中所有操作都与用户密切相关,是一个负责与用户交互的组件,可以通过setContentView(View)来显示指定控件。 在一个android应用中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。Activity之间通过Intent进行通信。 2. Activity之间的跳转(★★★★)Activity之间的跳转分为2种: 显式跳转:在可以引用到那个类, 并且可以引用到那个类的字节码时可以使用。一般用于自己程序的内部。显式跳转不可以跳转到其他程序的页面中。 隐式跳转:可以在当前程序跳转到另一个程序的页面。隐式跳转不需要引用到那个类,但是必须得知道那个界面的动作(action)和信息(category)。 Activity之间通过Intent进行通信。Intent即意图,用于描述一个页面的信息,同时也是一个数据的载体。 案例-显式跳转:显式跳转必须知道并且能够使用要跳转的Activity的字节码,所以显式跳转一般只能用于自己程序的内部的跳转,而不能跳转到其他程序的Activity。 :为了方便演示,我们创建一个新的Android工程《Activity跳转》。然后创建两个Activity类,分别为FirstActivity,和SecondActivity,并在Android工程清单文件中声明这两个Activity类。工程清单中添加Activity配置如下。 修改FirstActivity布局文件(activity_first.xml),并将该布局文件复制并修改名字为activity_second.xml作为SecondActivity的布局文件。 2.1显式跳转编写FirstActivity类: 运行上面的工程,点击按钮,发现成功跳转到了第二个Activity页面。 2.2隐式跳转隐式跳转可以跳转到其他程序的Activity,只要知道Activity的动作(action)以及信息(category)。因此,能够被隐式跳转的Activity,在清单文件中声明时必须指定动作和信息这两个属性。 修改工程清单文件中SecondActivity的配置信息。 修改在2.1章节中FirstActivity类 执行上面的代码,发现实现了Activity的跳转。 :若清单文件中的Activity声明为: 则此Activity将作为程序的入口,有几个作为入口的Activity,apk文件安装的时候就会生成几个图标。
3. 案例-Activity隐式跳转(★★★)Android系统中本身存在很多的应用程序,打开系统源码,查看packages文件夹下的apps文件夹,里面存放着Android系统的这些应用程序。 若想跳转到这些应用程序中,只需打开对应应用程序的清单文件,找到其动作和信息,采用隐式跳转即可实现。 3.1打开浏览器界面自己将Android应用的源码安装在:D:\AndroidSource_GB\AndroidSource_GB中,打开D:\AndroidSource_GB\AndroidSource_GB\packages\apps\Browser目录,然后打开AndroidManifest.xml清单文件,找到用于启动浏览器的intent-filter。 :intent-filter有多个,我们选择一个适合我们即可。 :为了方便演示我们直接修改本文档2.1章节中创建的工程,在FirstActivity的布局文件中添加一个按钮,点击该按钮打开一个浏览器。这里给出FirstActivity类核心方法的代码清单:
运行上面代码,发现成功跳转到了浏览器界面,并打开了指定的网页。 3.2打开短信发送界面打开Android应用源码,找到D:\AndroidSource_GB\AndroidSource_GB\packages\apps\Mms目录,打开AndroidManifest.xml清单文件,找到intent-filter。 在本文档2.1章节中给FirstActivity布局文件添加一个按钮,并添加按钮事件。在该方法中实现核心业务逻辑。 运行上面的代码,发现成功打开了短信发送界面。这里就不给出运行效果图。
4. 使用Intent传递数据(★★★★)Intent可传递的数据类型有: 八大基本类型 ,数组,ArrayList<String>, Bundle数据捆, 序列化接口(javabean)。 :Intent传递的数据过多可能会造成跳转速度极慢甚至黑屏一会,不要用Intent 传递过多的数据,会影响到应用程序的使用。 下面通过一个案例来演示Intent如何传递数据,我们依然使用2.1章节中的工程。需求:点击FirstActivity界面的按钮,将数据传递到SecondActivity,并显示传递的数据。 修改AndroidManifest.xml文件中SecondActivity的intent-filter参数 在FirstActivity布局中添加一个按钮,给该按钮绑定事件,点击该按钮实现跳转到SecondActivity界面。该事件核心方法清单如下: 编写SecondActivity类,使其接收数据。 运行该工程,发现成功跳转到了SecondActivity界面,同时控制台也成功打印出了通过Intent传递数据。如下图: 5. 案例-人品计算器(★★)知识点: - 跳转时使用startActivityForResult方法开启新页面
- 在被开启的新的页面里, 调用setResult方法设置回传的数据.
注意:设置完后不会立刻传递到前一个页面,而是等待当前页面关闭后, 才会 回传数据。 3. 回传数据给传递给前一个页面的onActivityResult方法,在此方法中对数据进行处理即可。 需求:在MainActivity页面中输入用户名,点击计算跳转到计算页面,计算页面计算完毕后将计算结果返回给MainActivity界面,该界面将计算结果显示出来。 创建一个新工程《人品计算器》,使用默认的Activity和默认的布局文件,修改布局文件。activity_main.xml布局清单如下: :上面布局文件采用相对布局,其中android:background="@drawable/rp" 属性是给界面设置背景图片,因此需要我们将图片添加到/res/drawable-hdpi目录下面。 android:visibility="invisible"属性是设置该控件不显示,显示的时候我们可以通过代码来实现其显示。 编写MainActivity核心代码类 新建CalcActivity类继承Activity类,并在AndroidManifest.xml中添加该类。 :上面代码中的getRPText方法大家在练习的时候直接拷贝即可,没必要再重新写一遍。 运行上面的工程,启动后页面左侧图,输入名字后点击计算,结果如右侧图。
6. Activity生命周期(★★★★)Activity有三种状态: 1、当它在屏幕前台时,响应用户操作的Activity, 它是激活或运行状态 2、当它上面有另外一个Activity,使它失去了焦点但仍然对用户可见时, 它处于暂停状态。 3、当它完全被另一个Activity覆盖时则处于停止状态。 当Activity从一种状态转变到另一种状态时,会调用以下保护方法来通知这种变化: 方法名 | 说明 | void onCreate() | 设置布局以及进行初始化操作 | void onStart() | 可见, 但不可交互 | void onRestart() | 调用onStart() | void onResume() | 可见, 可交互 | void onPause() | 部分可见, 不可交互 | void onStop() | 完全不可见 | void onDestroy() | 销毁 |
Activity生命周期图:
1、startActivity开启一个Activity时, 生命周期的过程是: onCreate ->onStart(可见不可交互) ->onResume(可见可交互) 2、点击back键关闭一个Activity时, 生命周期的过程是: onPause(部分可见不可交互)->onStop(完全不可见)->onDestroy(销毁) 3、当开启一个新的Activity(以对话框形式), 新的activity把后面的activity给盖住一部分时, 后面的activity的生命周期执行的方法是: onPause(部分可见, 不可交互) 注:指定Activity以对话框的形式显示, 需在activity节点追加以下主题 android:theme="@android:style/Theme.Dialog" 4、当把新开启的Activity(以对话框形式)给关闭时, 后面的activity的生命周期执 行的方法是: onResume(可见, 可交互) 5、当开启一个新的activity把后面的activity完全盖住时, 生命周期的方法执行顺 序是: onPause ->onStop(完全不可见) 6、当把新开启的activity(完全盖住)给关闭时, 生命周期的方法执行顺序是: onRestart ->onStart ->onResume(可见, 可交互) :实际工作中常用的方法以及应用场景有: onResume 可见, 可交互.。把动态刷新的操作启动。 onPause 部分可见, 不可交互. 把动态刷新的一些操作, 给暂停了。 onCreate 初始化一些大量的数据。 onDestroy 把数据给释放掉, 节省内存。 6.1横竖屏切换时Activity的生命周期横竖屏切换时,默认情况下会把activity先销毁再创建,在类似手机游戏这一类的应用中,这个体验是非常差的。不让Activity在横竖屏切换时销毁,只需要在清单文件声明Activity时配置<activity>节点的几个属性即可,其方式如下: 4.0以下版本: 4.0以上版本: 兼容所有版本 7. Activity的任务栈(★★★★)任务栈是用来提升用户体验而设计的: (1)程序打开时就创建了一个任务栈, 用于存储当前程序的activity,所有的activity属于一个任务栈。 (2)一个任务栈包含了一个activity的集合, 去有序的选择哪一个activity和用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。 (3)任务栈可以移动到后台, 并且保留了每一个activity的状态. 并且有序的给用户列出它们的任务, 而且还不丢失它们状态信息。 (4)退出应用程序时:当把所有的任务栈中所有的activity清除出栈时,任务栈会被销毁,程序退出。 任务栈的缺点: (1)每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用,户体验差, 需要点击多次返回才可以把程序退出了。 (2)每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)。
:为了解决任务栈产生的问题,Android为Activity设计了启动模式,那么下面的内容将介绍Android中Activity的启动模式,这也是最终要的内容之一。 8. Activity的启动模式(★★★★)启动模式(launchMode)在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。这里简单介绍一下task的概念,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。 Activity一共有以下四种launchMode: 1.standard 2.singleTop 3.singleTask 4.singleInstance 我们可以在AndroidManifest.xml配置<activity>的android:launchMode属性为以上四种之一即可。 下面我们结合实例一一介绍这四种lanchMode: 8.1 standardstandard模式是默认的启动模式,不用为<activity>配置android:launchMode属性即可,当然也可以指定值为standard。 我们将创建一个Activity,命名为FirstActivity,来演示一下标准的启动模式。FirstActivity代码如下: FirstActivity界面中的TextView用于显示当前Activity实例的序列号,Button用于跳转到下一个FirstActivity界面。 然后我们连续点击几次按钮,将会出现下面的现象: 我们注意到都是FirstActivity的实例,但序列号不同,并且我们需要连续按后退键两次,才能回到第一个FirstActivity。standard模式的原理如下图所示: 如图所示,每次跳转系统都会在task中生成一个新的FirstActivity实例,并且放于栈结构的顶部,当我们按下后退键时,才能看到原来的FirstActivity实例。 这就是standard启动模式,不管有没有已存在的实例,都生成新的实例。 8.2 singleTop我们在上面的基础上为<activity>指定属性android:launchMode="singleTop",系统就会按照singleTop启动模式处理跳转行为。我们重复上面几个动作,将会出现下面的现象: 我们看到这个结果跟standard有所不同,三个序列号是相同的,也就是说使用的都是同一个FirstActivity实例;如果按一下后退键,程序立即退出,说明当前栈结构中只有一个Activity实例。singleTop模式的原理如下图所示: 正如上图所示,跳转时系统会先在栈结构中寻找是否有一个FirstActivity实例正位于栈顶,如果有则不再生成新的,而是直接使用。也许朋友们会有疑问,我只看到栈内只有一个Activity,如果是多个Activity怎么办,如果不是在栈顶会如何?我们接下来再通过一个示例来证实一下大家的疑问。 我们再新建一个Activity命名为SecondActivity,如下: 然后将之前的FirstActivity跳转代码改为: 这时候,FirstActivity会跳转到SecondActivity,SecondActivity又会跳转到FirstActivity。演示结果如下: 我们看到,两个FirstActivity的序列号是不同的,证明从SecondActivity跳转到FirstActivity时生成了新的FirstActivity实例。原理图如下: 我们看到,当从SecondActivity跳转到FirstActivity时,系统发现存在有FirstActivity实例,但不是位于栈顶,于是重新生成一个实例。 这就是singleTop启动模式,如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。 8.3 singleTask在上面的基础上我们修改FirstActivity的属性android:launchMode="singleTask"。演示的结果如下: 我们注意到,在上面的过程中,FirstActivity的序列号是不变的,SecondActivity的序列号却不是唯一的,说明从SecondActivity跳转到FirstActivity时,没有生成新的实例,但是从FirstActivity跳转到SecondActivity时生成了新的实例。singleTask模式的原理图如下图所示: 在图中的下半部分是SecondActivity跳转到FirstActivity后的栈结构变化的结果,我们注意到,SecondActivity消失了,没错,在这个跳转过程中系统发现有存在的FirstActivity实例,于是不再生成新的实例,而是将FirstActivity之上的Activity实例统统出栈,将FirstActivity变为栈顶对象,显示到幕前。也许朋友们有疑问,如果将SecondActivity也设置为singleTask模式,那么SecondActivity实例是不是可以唯一呢?在我们这个示例中是不可能的,因为每次从SecondActivity跳转到FirstActivity时,SecondActivity实例都被迫出栈,下次等FirstActivity跳转到SecondActivity时,找不到存在的SecondActivity实例,于是必须生成新的实例。但是如果我们有ThirdActivity,让SecondActivity和ThirdActivity互相跳转,那么SecondActivity实例就可以保证唯一。 这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。 8.4 singleInstance这种启动模式比较特殊,因为它会启用一个新的栈结构,将Activity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。 我们修改FirstActivity的launchMode="standard",SecondActivity的launchMode="singleInstance",由于涉及到了多个栈结构,我们需要在每个Activity中显示当前栈结构的id,所以我们为每个Activity添加如下代码: 然后我们再演示一下这个流程: 我们发现这两个Activity实例分别被放置在不同的栈结构中,关于singleInstance的原理图如下 我们看到从FirstActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构;图中下半部分显示的在SecondActivity中再次跳转到FirstActivity,这个时候系统会在原始栈结构中生成一个FirstActivity实例,然后回退两次,注意,并没有退出,而是回到了SecondActivity,为什么呢?是因为从SecondActivity跳转到FirstActivity的时候,我们的起点变成了SecondActivity实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构。 如果我们修改FirstActivity的launchMode值为singleTop、singleTask、singleInstance中的任意一个,流程将会如图所示: singleInstance启动模式可能是最复杂的一种模式,为了帮助大家理解,我举一个例子,假如我们有一个share应用,其中的ShareActivity是入口Activity,也是可供其他应用调用的Activity,我们把这个Activity的启动模式设置为singleInstance,然后在其他应用中调用。我们编辑ShareActivity的配置: 然后我们在其他应用中这样启动该Activity: 当我们打开ShareActivity后再按后退键回到原来界面时,ShareActivity做为一个独立的个体存在,如果这时我们打开share应用,无需创建新的ShareActivity实例即可看到结果,因为系统会自动查找,存在则直接利用。大家可以在ShareActivity中打印一下taskId,看看效果。关于这个过程,原理图如下:
|