详解 Android 的 Activity 组件
和 J2ME 的 MIDlet 一样,在 android 中,Activity 的生命周期交给系统统一管理。与 MIDlet 不同的是安装在 android 中的所有的 Activity 都是平等的。
在 android 中,Activity 拥有四种基本状态:
- Active/Runing一个新 Activity 启动入栈后,它在屏幕最前端,处于栈的最顶端,此时它处于可见并可和用户交互的激活状态。
- Paused 当 Activity 被另一个透明或者 Dialog 样式的 Activity 覆盖时的状态。此时它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互。
- Stoped 当 Activity 被另外一个 Activity 覆盖、失去焦点并不可见时处于 Stoped状态。
- Killed Activity 被系统杀死回收或者没有被启动时处于 Killed状态。
当一个 Activity 实例被创建、销毁或者启动另外一个 Activity 时,它在这四种状态之间进行转换,这种转换的发生依赖于用户程序的动作。下图说明了 Activity 在不同状态间转换的时机和条件:
图 1. Activity 的状态转换
![图 1. Activity 的状态转换](https://i-blog.csdnimg.cn/blog_migrate/60429a3b0c691cc9698a10923245b542.png)
如上所示,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。
Android 是通过一种 Activity 栈的方式来管理 Activity 的,一个 Activity 的实例的状态决定它在栈中的位置。处于前台的 Activity 总是在栈的顶端,当前台的 Activity 因为异常或其它原因被销毁时,处于栈第二层的 Activity 将被激活,上浮到栈顶。当新的 Activity 启动入栈时,原 Activity 会被压入到栈的第二层。一个 Activity 在栈中的位置变化反映了它在不同状态间的转换。Activity 的状态与它在栈中的位置关系如下图所示:
图 2. Activity 的状态与它在栈中的位置关系
![图 2. Activity 的状态与它在栈中的位置关系](https://i-blog.csdnimg.cn/blog_migrate/d932ef258ce8649c85a843895b9fe62e.png)
如上所示,除了最顶层即处在 Active 状态的 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. 这些方法的调用时机
![图 3. 这些方法的调用时机](https://i-blog.csdnimg.cn/blog_migrate/aad1f13b347535d941c6ece8ae844fea.png)
此外,Android 还定义了一些不常用的与生命周期相关的方法可用:
protected void onPostCreate(Bundle savedInstanceState); protected void onRestart(); protected void onPostResume(); |
Android 提供的文档详细的说明了它们的调用规则。
在 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.startActivity()方法可以根据传入的参数启动另外一个 Activity:
Intent intent =new Intent(CurrentActivity.this,OtherActivity.class); startActivity(intent); |
当然,OtherActivity同样需要在 AndroidManifest.xml 中定义。
在 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 使用 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 方式。
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 的匹配过程
![图 4. Activity 种 Intent Filter 的匹配过程](https://i-blog.csdnimg.cn/blog_migrate/f07db412c25c2f58784378f1c2e12893.png)
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 提供的文档中找到它们的详细说明。
一个 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 数据匹配才会成功。
<intent-filter >节点中可以为组件定义一个 Category 类别列表,当 Intent 中包含这个列表的所有项目时 Category 类别匹配才会成功。
Android 内置了方向感应器的支持。在 G1 中,Android 会根据 G1 所处的方向自动在竖屏和横屏间切换。但是有时我们的应用程序仅能在横屏 / 竖屏时运行,比如某些游戏,此时我们需要锁定该 Activity 运行时的屏幕方向,<activity >节点的 android:screenOrientation属性可以完成该项任务,示例代码如下:
<activity android:name=".EX01" android:label="@string/app_name" android:screenOrientation="portrait">// 竖屏 , 值为 landscape 时为横屏 ………… </activity> |
要使一个 Activity 全屏运行,可以在其 onCreate()方法中添加如下代码实现:
// 设置全屏模式 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 去除标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE); |
为了更友好的用户体验,在处理一些需要花费较长时间的任务时可以使用一个进度条来提示用户“不要着急,我们正在努力的完成你交给的任务”。如下图:
在 Activity 的标题栏中显示进度条不失为一个好办法,下面是实现代码:
// 不明确进度条 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.main); setProgressBarIndeterminateVisibility(true); // 明确进度条 requestWindowFeature(Window.FEATURE_PROGRESS); setContentView(R.layout.main); setProgress(5000);
*******************************************************************************************************************************************
非个人原因,想换工作了,所以想弄点关于android面试题,网上有很多都是转载的,只有题没有答案的也有很多,所以想从网上找找整理一下,并且把答案整理一下(答案自己找的):
- 什么是Activity?
- Activity是Android程序的4大组件之一。
- Activity是Android程序的表示层。程序的每一个显示屏幕就是一个Activity。
- 学过WEB开发的同学,可以把Activity理解成网页中的一个JSP文件;或者你可以把它理解成一个Windows的窗口。
- 下面看一下Activity类的继承关系:
- 从这里可以看到Activity是Context类的子类
- 请描述一下Activity生命周期。
- 手机最重要也是最基础的功能是打电话,也就意味着电话来的时候可能随时要把现在的程序暂停,如果电量不足的时候也可能随时要把现有程序关闭;因此Android程序和电脑上的程序有所不同,具体到Activity,Activity的生命周期不是自身控制的,而是由Android系统控制的。
- 在android中Activity有四种基本状态:
- 1、Running
- 位于屏幕最前端时,此时处于可见状态,和用户可交互的状态。
- 2、Paused
- 当Acitivy被另一个透明的或者非全屏的Activity覆盖时的状态叫Paused状态,虽然可见但不可交互。
- 3、Stop
- 当Activity被另外一个Activity覆盖、界面不可见时处于Stop状态。
- 4、Killed
- Activity被系统杀死或者跟本没启动时就是Killed状态。
- 我们下面看一下Activity的生命周期:
- Activity栈:
- Android通过Activity栈的方式来管理Activity。
- 正在运行的Activity 处在在栈的最顶端,它是运行状态的;
- 当有新Activity进入屏幕最上端时,原来的Activity就会被压入第二层,如果他的屏幕没有被完全遮盖,那么他处于Pause状态,如果他被遮盖那么他处于Stop状态。
- 当然不管你出于任何一层,都可能在系统觉得资源不足时被强行关闭,当然关闭时在栈底的程序最先被关闭。
- 譬如:当你在程序中调用 Activity.finish()方法时,结果和用户按下 BACK 键一样:他告诉 Activity Manager该Activity实例可以被“回收”。随后 Activity Manager 激活处于栈第二层的 Activity 并重新入栈,把原 Activity 压入到栈的第二层,从 Running 状态转到 Paused 状态。
- 两个Activity之间跳转时必然会执行的是哪几个方法。
- startActivity(Intent intent) ;
- startActivityForResult (Intent intent, int requestCode) ;
- onActivityResult (int requestCode, int resultCode, Intent data);
- setResult(int resultCode);
- Intent intent = new Intent();
- intent.setClass(this.xxActivity,xxxActivity.class);
- this.startActivity(intent);
- 横竖屏切换时候Activity的生命周期。
- 如何将一个Activity设置成窗口的样式。
- 你后台的Activity被系统 回收怎么办?
- 如何退出Activity?如何安全退出已调用多个Activity的Application?
- 如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?
- 两个Activity之间怎么传递数据?
- 怎么让在启动一个Activity是就启动一个service?
- 同一个程序,但不同的Activity是否可以放在不同的Task任务栈中?
- Activity怎么和service绑定,怎么在activity中启动自己对应的service?
- 什么是Service以及描述下它的生命周期。
- Service有哪些启动方法,有什么区别,怎样停用Service?
- 不用service,B页面为音乐播放,从A跳转到B,再返回,如何使音乐继续播放?
- 什么是IntentService?有何优点?
- 什么时候使用Service?
- 请描述一下Intent 和 Intent Filter。
- Intent传递数据时,可以传递哪些类型数据?
- 说说Activity,Intent,Service是什么关系 。
- 请描述一下Broadcast Receiver。
- 在manifest和代码中如何注册和使 用 broadcast receiver 。
- 请介绍下ContentProvider是如何实现数据共享的。
- 请介绍下Android的数据存储方式。
- 为什么要用ContentProvider?它和sql的实现上有什么差别?
- 请介绍下Android中常用的五种布局。
- 谈谈UI中, Padding和Margin有什么区别?
- widget相对位置的完成在antivity的哪个生命周期阶段实现。
- 请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。
- AIDL的全称是什么?如何工作?能处理哪些类型的数据?
- 请解释下Android程序运行时权限与文件系统权限的区别。
- 系统上安装了多种浏览器,能否指定某浏览器访问指定页面?
- 对多线程的运用和理解,及多线程之间handle的传值。
- 对android虚拟机的理解,包括内存管理机制垃圾回收机制。
- Framework工作方式及原理,Activity是如何生成一个view的,机制是什么。
-
android本身的一些限制,比如apk包大小限制,读取大文件时的时间限。 - 如何加载的音乐信息,如何改善其效率。
- ListView如何提高其效率?
- 启动应用后,改变系统语言,应用的语言会改变么?
- 启动一个程序,可以主界面点击图标进入,也可以从一个程序中跳转过去,二者有什么区别?
- Android程序与Java程序的区别?
- Android中Task任务栈的分配。
- 在Android中,怎么节省内存的使用,怎么主动回收内存?
- 不同工程中的方法是否可以相互调用?
- 在Android中是如何实现判断区分通话记录中的电话状态,去电,来电、未接来电?
- dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念
- sim卡的EF 文件有何作用
- 如何判断是否有SD卡?
- 嵌入式操作系统内存管理有哪几种, 各有何特性。
- 什么是嵌入式实时操作系统, Android 操作系统属于实时操作系统吗?
- 一条最长的短信息约占多少byte?
- Linux中跨进程通信的几种方式 。
- 谈谈对Android NDK的理解。
- 谈谈Android的优点和不足之处。
- Android系统中GC什么情况下会出现内存泄露呢?
- Android UI中的View如何刷新。
- 简单描述下Android 数字签名。
- 什么是ANR 如何避免它?
- android中的动画有哪几类,它们的特点和区别是什么?
- handler机制的原理。
- android中线程与线程,进程与进程之间如何通信。
- 说说mvc模式的原理,它在android中的运用。
- android中有哪几种解析xml的类,官方推荐哪种?以及它们的原理和区别。
- DDMS与TraceView的区别?
- res目录有默认几项resource。
- android的哪个版本是一次重大的升级?