A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 王震阳老师 于 2015-3-23 22:21 编辑

Android基础-06Activity












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 standard
standard模式是默认的启动模式,不用为<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,看看效果。关于这个过程,原理图如下:



155 个回复

倒序浏览
沙发一楼
回复 使用道具 举报
这些都是手活吗?
回复 使用道具 举报
vayne 发表于 2015-3-12 16:08
这些都是手活吗?

难道电脑还能自动生成?:)
回复 使用道具 举报
大赞,啦啦啦啦
回复 使用道具 举报
每天都逛帖,赞一个~很不错
回复 使用道具 举报
鹏少 来自手机 中级黑马 2015-3-12 23:54:39
7#
赞赞,。。。
回复 使用道具 举报
怒赞一个!
回复 使用道具 举报
给力的阳哥专栏
回复 使用道具 举报
好大的信息量啊!~~~~~~~~~~~
回复 使用道具 举报

哈哈,多谢点赞啦
回复 使用道具 举报
粘糊浆 发表于 2015-3-13 11:13
好大的信息量啊!~~~~~~~~~~~

有吗?
回复 使用道具 举报
哈哈,只是想楼主关注下,能不能技术分上支持下我。:)
回复 使用道具 举报
手活不错,而且收获良多~~
回复 使用道具 举报
粘糊浆 发表于 2015-3-13 11:22
哈哈,只是想楼主关注下,能不能技术分上支持下我。

回答我出的技术分题才有技术分。
回复 使用道具 举报
信息量好大!!!
回复 使用道具 举报
阳哥技术这么好,照片怎么拍那么烂啊,背光啊
回复 使用道具 举报
已开班了看这样子
回复 使用道具 举报
已开班了看这样子
回复 使用道具 举报
看样子不容易
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马