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 个回复

正序浏览

已开班了看这样子
回复 使用道具 举报
我要好好学习
一定要好好学习
回复 使用道具 举报
牛啊6666666666
回复 使用道具 举报
很不错,相信黑马会越来越好
回复 使用道具 举报
每天都逛帖,赞一个~很不错
回复 使用道具 举报
已收藏...
回复 使用道具 举报
压力山大
回复 使用道具 举报
下载loud
回复 使用道具 举报
非常给力!
回复 使用道具 举报
有时间得好好研究研究
回复 使用道具 举报
一直关注中.........
回复 使用道具 举报
楼主强大,支持楼主,欢迎学习!
回复 使用道具 举报
好大信息量啊
回复 使用道具 举报
MrFly 初级黑马 2015-12-22 02:07:50
138#
学好基础是关键
回复 使用道具 举报
666666666666
回复 使用道具 举报
顶一个!
回复 使用道具 举报
小案例不错
回复 使用道具 举报
好东西!!!
回复 使用道具 举报
好给力——————
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马