1.1 深入了解Android的Activities
为了创建用户交互屏,你需要集成Activity类,使用Views去提供UI交互界面让用户进行交互操作。
每个Activity展现了一个屏幕(与表单很像),是应用用来给用户展示的。你的应用越是复杂,你可能需要的屏幕就越多。
为每个你想展示的界面创建一个Activity。典型做法是这里必须包含至少一个主要的screen接口用来处理应用主要的UI功能。这个主要的接口通常被另外一个用来输入信息,提供不同角度的书以及支持额外功能的Activity支持。以此来进行屏幕的切换。
大多数的Activities被设计成全屏的,但是也能创建半透明或者浮动的Activities。
1.1.1 创建Activity
创建一个继承Activity类的新类,在这个新类中你必须实现用户接口,并且实现你自己的功能。新Activity类的框架结构如图Listing 3-9所示:
图 Listing 3-9
Activity基类提供了一个空的screen,并且封装了窗口的展示处理。一个空的Activity是没什么用的。所以你最先想做的事情是用Views和layout去创建用户接口。
Views是用户接口的控制面板,用来展示数据和提供用户交互。Android提供了几个layout类,被称作 View Groups,他能包含多个Views去帮助你设计用户接口。
第四章会针对Views和View Group进行详细介绍,会介绍如何使用它们以及如何创建你自己的Views和layouts。
我们分配一个用户接口对应一个Activity,在Activity的onCreate中调用setContentView方法。
下边代码中,一个TextView实例被用作Activity的用户接口。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
setContentView(textView);
}
通常你会想去使用一个更加复杂的UI设计。通过使用layout View Groups 你可以在代码中创建一个layout,或者使用Android标准的方式,通过传递一个外部资源ID来定义layout。如下代码所示:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
为了在application中使用一个Activity,你必须在manifest中注册它。在manifest中的<application>标签内增加新的<activity>标签。<activity>标签包含一些元数据属性,例如label,icon,required permissions和被Activity使用的themes。如果Activity没有对应的<activity>标签,将不会被显示。
图Listing 3-10中显示了如何为图 Listing 3-9中展示的MyActivity类增加一个节点。
图 Listing 3-10
在<activity>标签内,你可以增加<intent-filter>节点,用来指定你的Activity将要监听和反馈的Intents.每个Intent Filter定了一个或者多个Activity要支持的动作以及分类。Intents和Intent Filters会在第五章进行深入探讨,但是值得注意的是,对于一个主程序加载的时候Activity必须可用,并且必须包含一个监听MAIN动作和LAUNCHAER分类的Intent Filter,如下图Listing 3-11 所示:
图 Listing 3-11
1.1.2 Activity生命周期
针对Activity生命周期的理解十分重要,他能帮你的应用提供一个无缝的用户体验并能适当的控制他的资源。
就像前边所说的那样,Android应用不控制他们自己的进程生命周期;Android运行时管理每个应用的进程,扩展来说管理每个进程中的Activity。
当运行时环境处理终止和Activity的进程管理时,Activity的状态帮我们确认application的优先级。application的优先级决定是否被终止的顺序,application内的Activity也随着application被终止而终止。
Activity stacks
每个Activity的状态是由他们在Activity stack上的位置决定的,原则是后进先出。当一个新的Activity启动了,当前前端的screen会被移动到堆栈的顶端。如果用户使用导航的back按钮或者当前前端的Activity被关闭了。那么在stack最上端的activity被变成活跃的。如图 3-6所示:
图 3-6
就像本章前边谈到的,application的优先级取决于它最高优先级的Activity。当Android的内存管理器决定哪个application应该被终止释放资源,它会基于这个stack上的activity去确认应用的优先级。
Activity states
就像图3-6展示那样,Activity在堆栈上移进移出的同时进行创建和销毁。当他们这样做的时候,他们会转变为如下四个状态。
Active:当一个Activity在堆栈的顶端的时候,他是可见的,获得焦点,在前端显示并能获取用户的输入。Android会不惜一切代价保持他的活跃状态,如有必要可以终止堆栈底层的Activities。当其他的Activity变得活跃,这个就会被暂停。
Paused:在某种情况下,你的Activity会是可见的,但是没有获取焦点,这种情况下就是paused状态。这种情况一般是在这个Activity前面有一个半透明或者非全屏的Activity。在paused情况下,activity被认为是活跃的。但是也有极端情况下paused状态的活动被终止以获取资源。当一个Activity变得完全看不见,那么他就到了stopped状态。
Stopped:当一个Activity不可见,他就变成“stopped”状态了。那么Activity还是会在内存中驻留,并且保持他所有的状态信息;但是当系统需要释放资源的时候,他就变成了候选者。所有当变成stopped状态的时候,去保留数据和当前UI状态是比较重要的。一旦Activity退出或者关闭,他就变成inactive状态了。
Inactive:在Activity被killed之后,在它没有冲加载之前,他是inactive状态。Inactive状态的Activity已经从堆栈中移除了,如果被展示使用是需要重启的。
状态转换是不能控制的,这个完全被Android的内存管理器控制。Android必要时会按照intactive-》stopped—》paused顺序释放资源终止应用。
注意:如果想要良好的用户体验,状态转换应该对用户透明,我们需要存储Activity在各种状态下的信息,以保证Activity重新转变为active状态时候能恢复相关值。
监控Activity改变
为了确保Activities能对状态的改变做出响应,Android提供了一系列的事件处理器,这些事件处理器在Activity状态转换的时候被触发。图3-7总结了这些生命周期当Activity的状态改变。
图 3-7
图Listing 3-12的代码框架展示了Activity状态改变时的一些事件防范。代码前的注释信息阐述了当状态改变的时候你需要考虑的事情。
图 Listing 3-12
如上边代码所示,你应该在每个事件处理器的覆盖方法的尾部调用superclass。
1.1.3 理解Activity生命时间
在一个Activity的全运行周期中,在创建和销毁之间,他会经历一次或者多次的活跃或者可见的状态。每个状态转换都会触发前边提到的处理函数。接下来我们针对这些阶段的生命周期以及事件会有一个深入的了解。
Full lifetime
你的Activity的全生命周期发生在第一次调用onCreate方法和最后一次调用onDestory方法。但是有些情况下Activity进程会被直接终止而不执行onDestory方法。
使用onCreate方法可以去初始化你的Activity:展示用户接口,引用类的变量,绑定数据,创建服务或者线程。onCreate方法被传入一个绑定了UI状态的对象,我们可以用这个对象去获取用户的上次状态。当然我们也需要在onSaveInstatncestate方法中保存用户的状态以供用户恢复状态。
覆盖onDestory方法可以清除onCreate方法中创建的资源,保证外部资源被关闭,例如网络和db链接的关闭。
作为Android编写高效代码的指导,它强烈建议编码创建短期的对象。快速的创建销毁对象会引发额外的垃圾回收,影响用户体验。如果你在程序中经常创建一些列同样的对象集合,考虑把他们放到onCreate方法中吧,在那里他们在整个Activity的生命周期中只被创建一次。
visible lifetime
可视化的生命周期是指Activity的状态在onStart和onStop之间转换。在这些状态下你的Activity将会对用户显示,虽然他们可能是局部显示或者无法获取焦点。Activities和可能精力多个可视化的生命周期,就像他们在前后台之间切换那样。虽然不常有,但是极端情况下,Activity会被终止而不会调用onStop方法。
onStop方法应该用来暂停或者停止动画、线程重力感应器,GPS,定时器、服务或者其他用来支撑用户接口的进程。当UI不可见的时候他会消耗较少的资源。当UI可见后,使用onStart(或者onRestart)方法去获取或者重启这些进程。
onRestart方法会优于除onStart外所有的方法率先被调用。可以用它去实现一些特定的处理。
onStart/onStop方法注册或者取消注册Broadcast Receiver(这些经常用来更新用户UI状态)。你将会在第五章的时候了解到更多关于使用Broadcast Receiver。
Active lifetime
active生命周期在调用onResume开始,在调用onPause结束。
一个活跃的Activity会在前端展示并且接收用户输入时间。你的Activity很可能他销毁前经历多个active生命周期。在一个新的Activity被展示的时候,当前active生命周期也会被终结,同样状况也有,设备休眠、失去焦点。我们要保证onPause方法和onResume方法中的代码高效迅速以保证application在前后端切换时响应迅速。
在调用onPause方法前我们会调用onSaveInstanceState。这个方法提供一个保存Activity UI状态的到Bundle中的机会。我们可以onCreate和onRestoreInstanceState方法中获取这个Bundle。以此恢复上次应用状态。
大多数的Activity实现都会至少覆盖onPause方法去提交没有保存的修改,以免应用被无警告的中止。这些取决于你应用的架构,当你的Activity不在前端的时候,你也许会选择线程挂起、进程挂起或者Broadcast Receivers
onResume方法可以是非常轻量级的。你不要再这里重新加载UI的状态,我们应该在onCreate和onRestoreInstanceState方法中重新加载UI状态。onResume是用来注册Broadcast Receiver或者其他你也许在onPause挂起的进程。
1.1.4 Android的Active类
Android SDK包含了一系列的Activity子类,封装了一些通用的用户接口组件。下边是一些常用的组件:
· MapActivity:封装了资源处理,这个需要Activity支持MapView组件
· ListActivity:针对数据资源封装了ListView,并且对外提供了数据列表项选中事件方法。
· ExpandableListActivity:和ListActivity类型,但是支持ExpandableListView
· TabActivity:内置多Activities或者在一个screen中通过tab组件切换
1.2 总结
这章你首先学会如何将这些松耦合的组件在manifest中组合使用。
你被介绍了Android的生命周期以及他们的优先级,以及他们的优先级取决于什么。
你学会了如何创建基于硬件配置、国际化、地区创建资源。
接下来你了解到Application的类,以及如何继承他,进行状态转换和数据传递。
然后介绍了关于Activities以及他们在application的角色。了解到如何创建Activities,他的生命周期。特别是状态转换,以及用户体验。
最后给你介绍了一些特别的Android Activity 类。