Android - Activity
Contents
Android组件:Activity、Service、Broadcast Receiver、Content Provider
Activity
Android中的Activity有四个基本状态:
- Actived/Runing 一个新的Activity被启动,处于Activity任务栈栈顶,显示在屏幕最前端,此时它处于可见并可和用户交互的激活状态。
- Paused 被另一个透明或者 Dialog 样式的 Activity 覆盖时的状态。仍然可见,但已失去焦点,不能与用户交互
- Stoped 被另一个Activity覆盖、不可见、失去焦点的状态。
- Killed/Destoryed 被系统回收,Activity实例被销毁
这些状态之间转换都依赖于用户的操作。程序员可以决定一个Activity何时启动,但不能决定它何时被销毁。
Activity生命周期方法
在android.app.Activity类中定义了一系列生命周期相关的方法,在应用自定义的Activity中只要复写了这些方法中所需的,就可以确保被android系统调用到。
- onCreate(Bundle savedInstanceState): 创建Activity时调用,在这里可以做一些初始化操作,如设置用户界面、读取savedInstanceState中的数据
- onStart(): 开启Activity。在上一个方法之后被调用,或者在stop状态转换成active状态时调用。如用户从前面一个Activity返回时。
- onResume(): 获取焦点。在上一个方法之后被调用,或在pause状态转换成activ状态时调用。如用户关闭对话框。
- onPause(): 失去焦点。在active状态转换成pause状态时调用。如用户打开了一个对话框时。
- onStop(): 停止Activity。从active状态转为stop状态。如用户打开了新的Activity。
- onDestory(): 结束Activity。被系统回收,一般在这里释放一些占有资源,如服务的连接。
生命周期方法可以分为以下三组:
- 完整生命周期(Entire lifetime):从
onCreate()
方法执行直到onDestroy()
结束。前者初始化,后者释放资源。 - 可视生命周期(Visible lifetime):从
onStart()
方法执行直到onStop()
结束。用户可见到Activity,即使它没有获取到焦点不能与用户交互,但可以在onStart()
中注册一个广播接 收者来接收用户的操作,在UI上做出相应的改变,然后在onStop()
中注销接受者。onStart()
和onStop()
可以被多次调用,完全取决于用户操作时Activity是否为用户可见。 - 前台生命周期(Foreground lifetime):从
onResume()
方法执行到onPause()
结束。Activity位于Activity任务栈顶端,并与用户进行交互。Activity经常会在paused和actived(/running)状态之间转换
保存Activity的状态
当系统内存不足,低优先级的应用进程会被系统Kill(如图所示),这时如果用户按了返回键想回到被回收的Activity,为了提高用户体验,那么系统就会重新启动这个Activity,可是这时的Activity中的数据可能已被销毁,这样,Android采用了一个能临时保存Activity数据的机制——将数据以键值对的形式存在一个Bundle对象中,系统将这个Bundle对象传给onCreate()
和onRestoreInstanceState()
,使用二者之一就可以很方便的从中获取数据展现给用户,如果Bundle对象为空,表明没有进行存放数据或者Activity才第一次被启动。
但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()
就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()
只适合用于保存一些临时性的状态,而onPause()
适合用于数据的持久化保存。
Activity任务栈(Task Stack)
Android 是通过Activity__任务栈__的方式来管理 Activity 的,一个 Activity 的实例的状态决定它在栈中的位置。
处于前台的 Activity 总是在栈的顶端,当新的 Activity 启动入栈时,原 Activity 会被压入到栈的第二层。当前台的 Activity 因为异常或其它原因被销毁时,处于栈第二层的 Activity 将被激活,上浮到栈顶。
一个 Activity 在栈中的位置变化反映了它在不同状态间的转换。
创建Activity
编写一个继承自 android.app.Activity的 Java 类并在 清单文件AndroidManifest.xml
声明即可。
1 | public class MainActivity extends Activity { |
AndroidManifest.xml片段:
1 | <activity android:name=".MainActivity" |
开启另一个Activity
通过startActivity()
方法可以根据传入的Intent*来开启另一个符合Intent的Activity(Activity都必须在清单文件中有定义)。
1 | Intent intent = new Intent(MainActivity.this,SecondActivity.class); |
*Intent见其详解。
Activity之间的通信
开启另一个Activity
Android用Intent对象来表示一条消息,一个Intent对象不仅包含这个消息的目的地,还可以包含消息的内容。目的地是必须的,而消息则是可选的,如同一封Email。
在MainActivity开启SecondActivity,并加入额外的内容:
1 | Intent intent = new Intent(MainActivity.this,SecondActivity.class); |
在SecondActivity中的接收这条消息:
1 | Intent intent = getIntent(); |
获得另一个Activity的返回数据
调用startActivityForResult(intent,requestCode)
开启一个新的Activity,新Activity执行完毕,可以根据请求码(requestCode)返回包装数据的Intent对象(intent),并给它指定响应码(responseCode),当前Activity就可以通过onActivityResult(requestCode,responseCode,intent)
来获取相应requestCode、responseCode和Intent对象中数据。
eg.
第一个Activity:
1 | public class MainActivity extends Activity { |
第二个Activity:
1 | public class NewActivity extends Activity { |
上面的setResult(responseCode,intent)
即用来设置返回数据的方法,第一个参数为响应码:RESULT_OK
是Activity定义的一个常量,其值为-1。
Activity的Intent Filter
在 Android 应用的 AndroidManifest.xml 清单文件中可以通过<intent-filter>
节点为一个 Activity 指定其 IntentFilter,以便告诉系统该 Activity 可以响应什么类型的 Intent。
当用startActivity(intent)
来启动一个Activity 时,Activity Manager 会在系统中检索与Intent 对象的属性(Action/Data Uri/Category)最为匹配的一个Activity 启动,如果没有找到则会抛出异常。
*具体详见Intent详解
其他
Activity的启动模式
在AndroidMamifest.xml 的<activity>
节点android:launchMode
属性设置。
默认值为standard:
每一次都会开启一个全新的Activity,加入任务栈。
singleTop的模式:
特点:
- 如果栈顶存在的Activity是要被激活的Activity他就不会再创建新的activity,直接在原有Activity上更新界面。
- 只有栈顶存在的Activity与要激活的singletop的Activity不相同的时候,才会创建新的activity放在任务栈的栈顶。
主要作用:就是为了避免糟糕的用户体验。避免一个被打开的界面,被重复的多次打开,用户要按多次的后退键才能退出这个应用程序。
singleTask的模式:
特点:在开启activity的时候,会检查任务栈里面是否已经有要激活的Activity的实例存在,如果存在的话,清空这个存在的Activity上面的任务,复用存在的这个Activity
应用场景:eg.浏览器: 初始化webkit内核(耗时耗空间),为了避免多次创建browser Activity的实例,消耗过多系统的内核和cpu,保证在当前应用程序的任务栈里面只有一个浏览器应用的activity的实例存在
singleInstance的模式:
特点:
- 这种模式非常的极端,不会把创建的Activity的实例放入到当前应用的任务栈里面。他会自己创建一个任务栈,并且在任务栈里存放自己的一个实例
- 在整个手机操作系统里面只有一个单独的任务栈,并且任务栈里面只有一个单独的实例存在
锁定Activity运行时屏幕方向
Android会自动根据内置重力感应器来切换横竖屏,在切换的时候,当前Activity会被destory后再重新启动另一个方向的全新的Activity,这样会极大影响一些应用的用户体验(比如游戏)。
此时,我们需要锁定该Activity运行时的屏幕方向,通过清单文件AndroidManifest.xml 中<activity>
节点的android:screenOrientation
属性来指定:landscape为横屏,portrait为竖屏。
eg.
1 | <activity android:name=".MainActivity" |
全屏Activity
可以在Activity的
onCreate()
实现方法中添加设置项(必须在setContentView()
之前设置)
全屏模式:1
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN , WindowManager.LayoutParams.FLAG_FULLSCREEN );
无标题栏:
1
requestWindowFeature(Window. FEATURE_NO_TITLE);
或者是在清单文件 AndroidManifest.xml 中的
节点添加android:theme属性:
全屏模式:android:theme=”@android:style/Theme.NoTitleBar.Fullscreen”
无标题栏:android:theme=”@android:style/Theme.NoTitleBar”
带进度条的标题栏
不明确任务的进度条:
1
2
3requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_main);
setProgressBarIndeterminateVisibility(true);明确任务的进度条:
1
2
3requestWindowFeature(Window. FEATURE_PROGRESS);
setContentView(R.layout. activity_main);
setProgress(5000);// 当前进度为5000,最大值为10000 (默认值)
Tips:
在<application>
节点也可以设置应用里所有的Activity的Theme。
更多的Activity样式配置可参见(Android控件主题样式的配置)
参考:
[1]https://www.ibm.com/developerworks/cn/opensource/os-cn-android-actvt/
[2]http://developer.android.com/intl/zh-CN/guide/components/activities.html
Author: Yrom
Link: https://yrom.net/blog/2011/12/14/android-activity/
License: 知识共享署名-非商业性使用 4.0 国际许可协议