Android开发之Activity 详解

这一篇我们主要讲下应用程序生命周期、Activity生命周期、Intent在Activity中的应用。

一、应用程序生命周期

与大多数传统的操作系统环境不同,Android应用程序并不能控制自己的生命周期。所以应用的各个组件(activity,Service……)就得时刻小心的监听应用的状态变化对它们的影响,防止在不适当的时机被终止掉。

在Android中每个应用都具有独立的进程运行在独立的Dalvik(Android特有的虚拟机)。各个应用在运行时的进程管理和内存管理都是相对独立的。Android使用一种"侵占性"的方式管理系统资源,这意味着为了释放资源给高优先级的程序(通常情况下是正在与用户进行直接交互的程序),某些进程及其宿主程序将会在没有任何提示警告的情况下被无情的结束。

理解应用的优先级和进程状态

结束一些进程是为了释放回收资源,那么那些进程会被结束?是A先结束还是B先结束呢?这决定于宿主应用程序的优先级了。一个应用的优先级等同于具有最高优先级的组件的优先级。如果此刻两个程序具有相同的优先级,那么曾经哪个进程处于低优先级的时间较长,就会被结束掉。进程的优先级受到进程间附属关系的影响,比如A应用依赖的Service或者Content Provider是由B应用提供的,那么B将会具有更高的优先级。所有的Android应用都会遗留在内存中运行,直到系统需要释放回收资源才会被结束掉。如图:各种进程及其对应的优先级。

Activity Process 活动进程是其宿主程序更用户直接交互的组件,Android会尝试通过回收各种资源来保证其运行状态。此类进程数量少,通常是最后被结束掉的。

活动进程包含下面几种:

  • Activity处于激活状态,也就是说处于foreground,接收响应用户事件
  • Activities, Services, or Broadcast Receivers 正在执行处理OnReceive 事件
  • Services 正在执行处理 onStart, onCreate, or onDestroy 事件

Visible Process 可视化,但是不处于活动状态的Activity。它们不处于foreground也不接受响应用户事件。这中情况发生在Activity有部分被覆盖了(比如我们点击A里面的一个按钮,弹出一个Dialog,此时A就变成一个可视进程)。可视进程同样很少,只有在极端的情况下,为了保证Activity Process的运行才会被结束掉。

Started Service Process 注意,是启动后的服务进程。服务进程需要在没有可视化界面的情况下持续运行,因为服务没有和用户直接交互。它们依然被认为是前台进程,只有当Visible和Activity Process需要资源的时候才会被结束。

Background Process 一个进程附属在不可视的Activity 也没有任何启动的服务进程就变成了后台进程。通常情况下Android里面会有一大堆后台进程,Android用 last-seen-first-killed 这种方式来结束此类进程,从而为foreground进程提供资源。

Empty Process 为了改善整个系统的性能,Android会在内存中保留已经结束生命周期的应用程序。Android保留这些缓存为了是应用能够快速启动。它们将会按照一贯的情况被结束掉。

综上所述,正确的组织应用程序,确保稳定运行,防止运行中途被终止是非常重要的。

二、Activity的生命周期

正确理解Activity的生命周期是非常重要的,只有正确理解Activity的生命周期,才能确保应用程序提供一个符合逻辑的的用户体验以及正确管理应用程序本身的资源。Android中的应用程序并不能管理自身的生命周期,而是由系统统一管理的,当然Activity也是这样子的。在运行时管理以及是否结束Activity进程,Activity的状态决定了应用程序的优先级。反过来,程序的优先级也影响着在运行时是否会终止Activity以及保持Activity持续运行。

1、活动栈

活动在栈中的位置决定了活动状态。当一个新的活动启动时,这个活动就会被当作前景屏幕,并被放到活动栈的栈顶。当用户触发"返回"事件或者前景活动关闭时,下一个活动就会移到栈顶并激活。如下图所示:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

之前说过,Android中应用程序的优先级是由其最高优先级的组件(一般就是Activity)决定的。因此当Android需要终止某些应用程序释放系统资源时,就依据活动栈来决定应用程序优先级的高低,从而终止那些低优先级的应用程序。

2、活动状态

  • 激活 当一个活动处于活动栈栈顶,它是可见的,可聚焦的,可接受用户的输入。Android会试图不惜一切代价,甚至是终止处于栈底的活动来回收资源,以保证栈顶活动对资源的需求。当有新的活动被激活,这个活动就会被暂停或者停止。
  • 暂停  活动可见,但是不能聚焦,此时活动就处于暂停状态。当活动暂停时无法接受用户事件。在极端的情况下,Android会终止一个处于暂停状态的活动,来回收系统资源。当一个活动被完全覆盖,它就处于停止状态。
  • 停止  当一个活动不可见,它就处于停止状态。活动会将状态和组件信息保留在内存中。当一个活动转入停止状态,我们需要保存数据和UI状态。一个活动关闭或者退出,就进入不活动状态。
  • 不活动(睡眠)  活动被关闭后,在重新启动之前就处于不活动状态。此状态的Activity并不会存在活动栈中,在显示和使用之前需要重新启动。

Activity状态的改变是不确定的,这是完全由Android的内存管理器控制的。Android会事先关闭那些含有处于睡眠状态,停止状态甚至是暂停状态活动的应用程序。为了提供一个良好的用户体验,Activity状态的改变对用户来说应该是透明的,所以当Activity进入暂停和停止状态,保存UI状态和持久化数据是很重要的。一旦活动重新激活,则恢复相关数据。

3、监听活动状态变化

为了确保对活动状态变化作出正确的响应,Android提供一个系列的事件控制器,监听活动的在整个生命周期的状态变化。活动的生命周期进一步细化,可以分为:全周期(Full Lifetime)>可视期(Visible Lifetime)>激活期(Active Lifetime),如下图所示:

 

 

 

 

 

 

 

 

 

 

如上图所示,Activity状态的改变都会触发对应的方法。

Full Lifetime 全周期介于调用 onCreate 与 onDestroy 之间。在一些情况下,终止一个活动并不调用 onDestroy 。Activity通过调用 onCreate 来初始化用户界面,数据,启动服务以及线程。onCreate 方法有个Bundle对象参数,这个参数含有最后一次调用 onSaveIntanceState 保存的UI状态数据。我们可以在 onCreate 中利用这个参数来恢复UI状态数据,或者重写 onRestoreInstanceState 。重写 onDestroy 释放资源,关闭数据库等操作。

为了写出比较高效的代码,有个比较好的建议是避免创建短期对象。快速的创建和销毁对象容易增加碎片回收线程的压力,这样会直接影响用户体验。

Visible Lifetime 可视期介于调用 onStart 与 onStop 之间。此时Activity是可见的,但是不能响应用户事件。一个Activity在其生命周期中是有可能经历多个可视期的。在非常极端的情况下,系统也有可能终止一个处于可视期的活动,这种情况很少见。onStop 方法通常用于暂时或者停止那些用来更新UI的动画,线程,定时器,服务等,所以当活动不可见的时占用的系统资源是很少的。当活动由不可见状态转化为可见状态时,在 onStart 中再启动相关的线程和服务。onStart 和 onStop 同样也用来注册和取消注册(unregister)那些用来更新UI的广播接收者。在活动不可见时我们需要取消注册接受者(Receivers),特别是那些支持目的动作(Intent)以及更新UI的接收者。

Activity Lifetime 当活动的 onResume 被调用,活动进入激活期;当 onPause 被调用时,激活期结束。一个活动被激活,它将处于前景屏幕,同时响应用户的事件。同样在活动的生命周期结束之前,存在多个激活期,一旦有新的活动被激活,当前活动将会失去焦点(暂停甚至停止……)。激活期是活动生命周期比较活跃的部分,会频繁调用 onResume 和 onPause ,所以为了有良好的用户体验,在 onResume 和 onPause 方法中的代码需要有更高的效率。

在调用 onPause 之前,活动会调用 onSaveInstanceState 来保存活动的UI状态到 Bundle ,这个 Bundle 就是 onCreate 和 onRestoreInstanceState 这两个方法的参数了。onSaveInstanceState 保存UI状态(比如多选按钮的状态,界面焦点=),这样当活动被重新激活时,能够正确显示被暂停前的UI。多数的活动都重写 onPause 方法来提交未保存的数据,我们也可以在此选择是否暂停线程,广播接收者,这完全依软件架构本身而定。在 onResume 中一般不执行太多的代码,创建UI一般在 onCreate 或者 onRestoreInstanceState 中实现。

三、Intent

Intent的中文意思是目的。在Android中也是"目的"的意思。就是我们要去哪里,从这个activity要前往另一个Activity就需要用到Intent。

示例代码一:

//定义一个Intent

Intent intent = new Intent(IntentDemo.this, AnotherActivity2.class);

//启动Activity

startActivity(intent);

以上示例代码的作用是从IntentDemo这个activity切换到AnotherActivity2。这是Intent其中一种构造方法,指定两个Activity。为什么需要指定两个活动呢?因为在Android中有一个活动栈,这样的构造方式才能确保正确的将前一个活动压入栈中,才能在触发返回键的时候活动能够正确出栈。

注意:所有的Activity都必须先在AndroidManifest.xml里面配置声明。一下为本文用到的程序配置文件

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.halzhang.android.intent" android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".IntentDemo" 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 android:name=".AnotherActivity" android:label="another">

<intent-filter>

<action android:name="android.intent.action.EDIT" />

<!-- category一定要配置,否则报错:找不到Activity -->

<category android:name="android.intent.category.DEFAULT" />

</intent-filter>

</activity>

 

<activity android:name=".AnotherActivity2" android:label="another2">

<intent-filter>

<action android:name="android.intent.action.EDIT" />

<category android:name="android.intent.category.DEFAULT" />

</intent-filter>

</activity>

</application>

<uses-sdk android:minSdkVersion="3" />

<!--

上面配置的两个activity具有相同的action类型,都为"android.intent.action.EDIT"

当Intent的action属性为Intent.ACTION_EDIT时,系统不知道转向哪个Activity时,

就会弹出一个Dialog列出所有action为"android.intent.action.EDIT"的

Activity供用户选择

-->

</manifest>

1、Intent的构造函数

公共构造函数:

1、Intent() 空构造函数

2、Intent(Intent o) 拷贝构造函数

3、Intent(String action) 指定action类型的构造函数

4、Intent(String action, Uri uri) 指定Action类型和Uri的构造函数,URI主要是结合程序之间的数据共享ContentProvider

5、Intent(Context packageContext, Class<?> cls) 传入组件的构造函数,也就是上文提到的

6、Intent(String action, Uri uri, Context packageContext, Class<?> cls) 前两种结合体

Intent有六种构造函数,3、4、5是最常用的,并不是其他没用!

Intent(String action, Uri uri)  的action就是对应在AndroidMainfest.xml中的action节点的name属性值。在Intent类中定义了很多的Action和Category常量。

示例代码二:

1: Intent intent = new Intent(Intent.ACTION_EDIT, null);

2: startActivity(intent);

示例代码二是用了第四种构造函数,只是uri参数为null。执行此代码的时候,系统就会在程序主配置文件AndroidMainfest.xml中寻找

<action android:name="android.intent.action.EDIT" />对应的Activity,如果对应为多个activity具有<action android:name="android.intent.action.EDIT" />此时就会弹出一个dailog选择Activity,如右图:

如果是用示例代码一那种方式进行发送则不会有这种情况。

2、利用Intent在Activity之间传递数据

在Main中执行如下代码:

Bundle bundle = new Bundle();

bundle.putStringArray("NAMEARR", nameArr);

Intent intent = new Intent(Main.this, CountList.class);

intent.putExtras(bundle);

startActivity(intent);

在CountList中,代码如下:

Bundle bundle = this.getIntent().getExtras();

String[] arrName = bundle.getStringArray("NAMEARR");

以上代码就实现了Activity之间的数据传递!

posted @ 2011-05-12 11:49  藏积  阅读(2083)  评论(0编辑  收藏  举报