详解 Android 的 Activity 组件
Activity 的生命周期
和 J2ME 的 MIDlet 一样,在 android 中,Activity 的生命周期交给系统统一管理。与 MIDlet 不同的是安装在 android 中的所有的 Activity 都是平等的。
Activity 的状态及状态间的转换
在 android 中,Activity 拥有四种基本状态:
-
Active/Runing
一个新 Activity 启动入栈后,它在屏幕最前端,处于栈的最顶端,此时它处于可见并可和用户交互的激活状态。
-
Paused
当 Activity 被另一个透明或者 Dialog 样式的 Activity 覆盖时的状态。此时它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互。
-
Stoped
当 Activity 被另外一个 Activity 覆盖、失去焦点并不可见时处于 Stop
ed
状态。
-
Killed
Activity 被系统杀死回收或者没有被启动时处于 Killed
状态。
当一个 Activity 实例被创建、销毁或者启动另外一个 Activity 时,它在这四种状态之间进行转换,这种转换的发生依赖于用户程序的动作。下图说明了 Activity 在不同状态间转换的时机和条件:
图 1. Activity 的状态转换
如上所示,Android 程序员可以决定一个 Activity 的“生”,但不能决定它的“死”,也就时说程序员可以启动一个 Activity,但是却不能手动的“结束”一个 Activity。当你调用 Activity.finish()
方
法时,结果和用户按下 BACK 键一样:告诉 Activity Manager 该 Activity 实例完成了相应的工作,可以被“回收”。随后
Activity Manager 激活处于栈第二层的 Activity 并重新入栈,同时原 Activity 被压入到栈的第二层,从
Active 状态转到 Paused 状态。例如:从 Activity1 中启动了 Activity2,则当前处于栈顶端的是
Activity2,第二层是 Activity1,当我们调用 Activity2.finish()
方法时,Activity Manager 重新激活 Activity1 并入栈,Activity2 从 Active 状态转换 Stoped 状态,Activity1. onActivityResult(int requestCode, int resultCode, Intent data)
方法被执行,Activity2 返回的数据通过 data
参数返回给 Activity1。
Activity 栈
Android 是通过一种 Activity 栈的方式来管理 Activity 的,一个 Activity
的实例的状态决定它在栈中的位置。处于前台的 Activity 总是在栈的顶端,当前台的 Activity
因为异常或其它原因被销毁时,处于栈第二层的 Activity 将被激活,上浮到栈顶。当新的 Activity 启动入栈时,原 Activity
会被压入到栈的第二层。一个 Activity 在栈中的位置变化反映了它在不同状态间的转换。Activity
的状态与它在栈中的位置关系如下图所示:
图 2. Activity 的状态与它在栈中的位置关系
如上所示,除了最顶层即处在 Active 状态的 Activity 外,其它的 Activity
都有可能在系统内存不足时被回收,一个 Activity 的实例越是处在栈的底层,它被系统回收的可能性越大。系统负责管理栈中 Activity
的实例,它根据 Activity 所处的状态来改变其在栈中的位置。
Activity 生命周期
在 android.app.Activity
类中,Android 定义了一系列与生命周期相关的方法,在我们自己的 Activity 中,只是根据需要复写需要的方法,Java 的多态性会保证我们自己的方法被虚拟机调用,这一点与 J2ME 中的 MIDlet 类似。
public class OurActivity extends Activity {
protected void onCreate(Bundle savedInstanceState);
protected void onStart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
}
|
这些方法的说明如下:
-
-
-
protected void onCreate(Bundle savedInstanceState)
一个 Activity 的实例被启动时调用的第一个方法。一般情况下,我们都覆盖该方法作为应用程序的一个入口点,在这里做一些初始化数据、设置用户界面等工作。大多数情况下,我们都要在这里从 xml 中加载设计好的用户界面。例如:
setContentView(R.layout.main);
|
当然,也可从 savedInstanceState
中读我们保存到存储设备中的数据,但是需要判断 savedInstanceState
是否为 null
,因为 Activity 第一次启动时并没有数据被存贮在设备中:
if(savedInstanceState!=null){
savedInstanceState.get("Key");
}
|
-
-
-
protected void onStart()
该方法在 onCreate() 方法之后被调用,或者在 Activity 从 Stop 状态转换为 Active 状态时被调用。
-
protected void onResume()
在 Activity 从 Pause 状态转换到 Active 状态时被调用。
-
protected void onResume()
在 Activity 从 Active 状态转换到 Pause 状态时被调用。
-
protected void onStop()
在 Activity 从 Active 状态转换到 Stop 状态时被调用。一般我们在这里保存 Activity 的状态信息。
-
protected void onDestroy()
在 Active 被结束时调用,它是被结束时调用的最后一个方法,在这里一般做些释放资源,清理内存等工作。
图 3. 这些方法的调用时机
此外,Android 还定义了一些不常用的与生命周期相关的方法可用:
protected void onPostCreate(Bundle savedInstanceState);
protected void onRestart();
protected void onPostResume();
|
Android 提供的文档详细的说明了它们的调用规则。
创建一个 Activity
在 android 中创建一个 Activity 是很简单的事情,编写一个继承自 android.app.Activity
的 Java 类并在 AndroidManifest.xml
声明即可。下面是一个为了研究 Activity 生命周期的一个 Activity 实例(工程源码见下载):
Activity 文件:
public class EX01 extends Activity {
private static final String LOG_TAG = EX01.class.getSimpleName();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.e(LOG_TAG, "onCreate");
}
@Override
protected void onStart() {
Log.e(LOG_TAG, "onStart");
super.onStart();
}
@Override
protected void onResume() {
Log.e(LOG_TAG, "onResume");
super.onResume();
}
@Override
protected void onPause() {
Log.e(LOG_TAG, "onPause");
super.onPause();
}
@Override
protected void onStop() {
Log.e(LOG_TAG, "onStop");
super.onStop();
}
@Override
protected void onDestroy() {
Log.e(LOG_TAG, "onDestroy ");
super.onDestroy();
}
}
|
AndroidManifest.xml 中通过 <activity> 节点说明 Activity,将 apk 文件安装后,系统根据这里的说明来查找读取 Activity,本例中的说明如下:
<activity android:name=".EX01" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
|
回页首
启动另外一个 Activity
Activity.startActivity()
方法可以根据传入的参数启动另外一个 Activity:
Intent intent =new Intent(CurrentActivity.this,OtherActivity.class);
startActivity(intent);
|
当然,OtherActivity
同样需要在 AndroidManifest.xml 中定义。
Activity 之间通信
使用 Intent 通信
在 Android 中,不同的 Activity
实例可能运行在一个进程中,也可能运行在不同的进程中。因此我们需要一种特别的机制帮助我们在 Activity 之间传递消息。Android 中通过
Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封
Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。
在上面的实例中通过 Activity. startActivity(intent)
启动另外一个 Activity 的时候,我们在 Intent 类的构造器中指定了“收件人地址”。
如果我们想要给“收件人”Activity 说点什么的话,那么可以通过下面这封“e-mail”来将我们消息传递出去:
Intent intent =new Intent(CurrentActivity.this,OtherActivity.class);
// 创建一个带“收件人地址”的 email
Bundle bundle =new Bundle();// 创建 email 内容
bundle.putBoolean("boolean_key", true);// 编写内容
bundle.putString("string_key", "string_value");
intent.putExtra("key", bundle);// 封装 email
startActivity(intent);// 启动新的 Activity
|
那么“收件人”该如何收信呢?在 OtherActivity
类的 onCreate()
或者其它任何地方使用下面的代码就可以打开这封“e-mail”阅读其中的信息:
Intent intent =getIntent();// 收取 email
Bundle bundle =intent.getBundleExtra("key");// 打开 email
bundle.getBoolean("boolean_key");// 读取内容
bundle.getString("string_key");
|
上面我们通过 bundle
对象来传递信息,bundle
维护了一个 HashMap<String, Object>
对象,将我们的数据存贮在这个 HashMap 中来进行传递。但是像上面这样的代码稍显复杂,因为 Intent 内部为我们准备好了一个 bundle
,所以我们也可以使用这种更为简便的方法:
Intent intent =new Intent(EX06.this,OtherActivity.class);
intent.putExtra("boolean_key", true);
intent.putExtra("string_key", "string_value");
startActivity(intent);
|
接收:
Intent intent=getIntent();
intent.getBooleanExtra("boolean_key",false);
intent.getStringExtra("string_key");
|
使用 SharedPreferences
SharedPreferences 使用 xml 格式为 Android 应用提供一种永久的数据存贮方式。对于一个 Android 应用,它存贮在文件系统的 /data/ data/your_app_package_name/shared_prefs/
目录下,可以被处在同一个应用中的所有 Activity 访问。Android 提供了相关的 API 来处理这些数据而不需要程序员直接操作这些文件或者考虑数据同步问题。
// 写入 SharedPreferences
SharedPreferences preferences = getSharedPreferences("name", MODE_PRIVATE);
Editor editor = preferences.edit();
editor.putBoolean("boolean_key", true);
editor.putString("string_key", "string_value");
editor.commit();
// 读取 SharedPreferences
SharedPreferences preferences = getSharedPreferences("name", MODE_PRIVATE);
preferences.getBoolean("boolean_key", false);
preferences.getString("string_key", "default_value");
|
其它方式
Android 提供了包括 SharedPreferences 在内的很多种数据存贮方式,比如 SQLite,文件等,程序员可以通过这些 API 实现 Activity 之间的数据交换。如果必要,我们还可以使用 IPC 方式。
Activity 的 Intent Filter
Intent Filter 描述了一个组件愿意接收什么样的 Intent 对象,Android 将其抽象为 android.content.IntentFilter 类。在 Android 的 AndroidManifest.xml 配置文件中可以通过 <intent-filter >
节点为一个 Activity 指定其 Intent Filter,以便告诉系统该 Activity 可以响应什么类型的 Intent。
当程序员使用 startActivity(intent) 来启动另外一个 Activity 时,如果直接指定 intent 了对象的
Component 属性,那么 Activity Manager 将试图启动其 Component 属性指定的 Activity。否则
Android 将通过 Intent 的其它属性从安装在系统中的所有 Activity 中查找与之最匹配的一个启动,如果没有找到合适的
Activity,应用程序会得到一个系统抛出的异常。这个匹配的过程如下:
图 4. Activity 种 Intent Filter 的匹配过程
Action 匹配
Action 是一个用户定义的字符串,用于描述一个 Android 应用程序组件,一个 Intent Filter 可以包含多个 Action。在 AndroidManifest.xml 的 Activity 定义时可以在其 <intent-filter >
节点指定一个 Action 列表用于标示 Activity 所能接受的“动作”,例如:
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<action android:name="com.zy.myaction" />
……
</intent-filter>
|
如果我们在启动一个 Activity 时使用这样的 Intent 对象:
Intent intent =new Intent();
intent.setAction("com.zy.myaction");
|
那么所有的 Action 列表中包含了“com.zy.myaction
”的 Activity 都将会匹配成功。
Android 预定义了一系列的 Action 分别表示特定的系统动作。这些 Action 通过常量的方式定义在 android.content. Intent
中,以“ACTION_
”开头。我们可以在 Android 提供的文档中找到它们的详细说明。
URI 数据匹配
一个 Intent 可以通过 URI 携带外部数据给目标组件。在 <intent-filter >
节点中,通过 <data/>
节点匹配外部数据。
mimeType 属性指定携带外部数据的数据类型,scheme 指定协议,host、port、path 指定数据的位置、端口、和路径。如下:
<data android:mimeType="mimeType" android:scheme="scheme"
android:host="host" android:port="port" android:path="path"/>
|
如果在 Intent Filter 中指定了这些属性,那么只有所有的属性都匹配成功时 URI 数据匹配才会成功。
Category 类别匹配
<intent-filter >
节点中可以为组件定义一个 Category 类别列表,当 Intent 中包含这个列表的所有项目时 Category 类别匹配才会成功。
一些关于 Activity 的技巧
锁定 Activity 运行时的屏幕方向
Android 内置了方向感应器的支持。在 G1 中,Android 会根据 G1 所处的方向自动在竖屏和横屏间切换。但是有时我们的应用程序仅能在横屏 / 竖屏时运行,比如某些游戏,此时我们需要锁定该 Activity 运行时的屏幕方向,<activity >
节点的 android:screenOrientation
属性可以完成该项任务,示例代码如下:
<activity android:name=".EX01"
android:label="@string/app_name"
android:screenOrientation="portrait">// 竖屏 , 值为 landscape 时为横屏
…………
</activity>
|
全屏的 Activity
要使一个 Activity 全屏运行,可以在其 onCreate()
方法中添加如下代码实现:
// 设置全屏模式
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 去除标题栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
在 Activity 的 Title 中加入进度条
为了更友好的用户体验,在处理一些需要花费较长时间的任务时可以使用一个进度条来提示用户“不要着急,我们正在努力的完成你交给的任务”。如下图:
在 Activity 的标题栏中显示进度条不失为一个好办法,下面是实现代码:
// 不明确进度条
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.main);
setProgressBarIndeterminateVisibility(true);
// 明确进度条
requestWindowFeature(Window.FEATURE_PROGRESS);
setContentView(R.layout.main);
setProgress(5000);
分享到:
相关推荐
### Android自定义组件解析 #### GDI介绍与作用 GDI(Graphics Device Interface),即图形设备接口,是操作系统中用于处理图形输出的关键组件。在Android环境中,GDI的主要职责在于管理和操作显示缓冲区,为上层GUI...
这个"Android系统原理与开发要点详解_培训课件.7z"压缩包文件包含了深入理解Android系统工作原理和开发实践的关键信息。让我们来详细探讨其中可能涵盖的知识点。 1. **Android系统架构**:Android系统基于Linux内核...
书中可能会详细介绍Android的四大组件(Activity、Service、Broadcast Receiver、Content Provider),UI设计,网络通信,数据库操作,权限管理等方面的知识。 “应用开发详解”意味着读者可以期待对整个开发流程的...
2. **Activity和Intent**:Activity是Android应用的基本组件,用于展示用户界面。Intent则作为组件间通信的桥梁,可以启动或传递数据给其他Activity。 3. **Service**:后台运行的服务,不与用户交互,但能长时间...
1. **Android Intent机制**:Intent是Android中用于组件间通信的关键机制,它允许应用程序启动其他组件,如Activity。攻击者可以通过构造恶意Intent,欺骗系统启动非预期的Activity,从而实现劫持。 2. **Intent ...
Android悬浮窗实现原理和WindowManager详解 Android悬浮窗是指在Android系统中,可以悬浮在屏幕上的一种窗口,常见于QQ视频、手机杀毒软件的桌面小助手等应用中。要实现悬浮窗,需要使用WindowManager来管理窗口。...
《Android滑动视图与标签实现详解》 在Android应用开发中,滑动视图(Swipe Views)和标签(Tabs)是常见的用户界面组件,它们为用户提供了一种便捷的方式来浏览和切换不同的内容区域。Android-swipe-views-tabs...
《Android俄罗斯方块游戏开发详解》 在移动设备上,Android平台因其开源性和广泛的设备覆盖范围,成为开发者们实现各种游戏应用的理想选择。本篇将深入探讨如何在Android环境中开发一款经典的俄罗斯方块游戏,涉及...
这篇博文“android 探索首选项框架xxxPreference”深入剖析了这一核心组件,通过源码分析和实践工具的应用,为开发者提供了一个更深入的理解。 首选项框架在Android中主要用于构建设置界面,它提供了多种预定义的UI...
7. **src**:这个目录包含了所有的源代码,包括Activity、服务、广播接收者等组件的Java或Kotlin文件。 8. **res**:资源文件夹,包含了应用的所有非代码资源,如布局XML文件、图片、字符串、颜色等。 9. **....
Android应用通常由一系列的组件(Activity、Service、BroadcastReceiver、ContentProvider)以及相应的资源文件(XML布局、图片、字符串等)组成。开发者使用Java或Kotlin语言编写代码,并借助Android Studio这样的...
**Android中的FlatBuffers详解** FlatBuffers是一种高效的序列化库,由Google开发,旨在提供比JSON、XML等传统格式更快的序列化和反序列化速度。它允许数据在无需解析整个结构的情况下直接访问,这对于游戏开发、...
【Android数字记忆游戏源码详解】 本项目是一个基于Android平台的数字记忆游戏,旨在帮助用户锻炼记忆力和反应速度。源码提供了完整的开发流程,对于学习Android应用开发的开发者来说,这是一个很好的实践案例。...
《基于Android Studio的人事管理系统详解》 Android Studio作为Google官方推荐的Android应用开发集成环境,以其强大的功能和友好的开发体验深受开发者喜爱。本压缩包“人事管理系统.7z”便是一个利用Android Studio...
6. **Kotlin与Android组件交互** 利用Kotlin的协程和LiveData,可以在后台处理数据存储,避免UI线程阻塞。LiveData可监听数据变化,自动更新UI,提供更好的用户体验。 7. **权限申请** 由于涉及到个人信息的录入...
【Android面试知识点详解】 1. **Padding和Margin的区别** Padding是元素内部的边距,用于设置元素内容与边框之间的距离,而Margin是元素与周围元素或父元素之间的距离,控制元素外边距。 2. **ListView效率优化*...
3. **Android组件**:包括Activity(界面)、Service(后台服务)、BroadcastReceiver(广播接收器)和ContentProvider(数据共享),是构建应用的核心。 4. **文件系统交互**:GetSDTree应用需要读取和显示SD卡文件...
- `Activity` 和 `Fragment` 是Android中的主要界面组件,分别用于全屏交互和可嵌入的UI片段。 5. **文件系统访问与媒体库集成**: - 访问本地音乐文件可能需要权限管理,通过`<uses-permission>`标签在`...
《Android集成阿里百川测试Demo详解》 在移动开发领域,尤其在Android平台,开发者常常需要集成各种第三方服务以提升应用的功能和用户体验。阿里百川是阿里巴巴集团提供的一站式移动开发解决方案,涵盖推送、统计...