招生热线
0755-86191118 0755-86191118
我的位置: 首页 > 学习专区 > 安卓技术 > Android: Activity 生命周期

Android: Activity 生命周期

2013-03-06 11:23:37
来源:
[导读] Activity生命周期 运行、暂停、停止。运行(获得了焦点)、暂停(失去了焦点、但是可见)、停止(失去了焦点、不可见)。中间有可见、不可
Activity生命周期 运行、暂停、停止。

运行(获得了焦点)、暂停(失去了焦点、但是可见)、停止(失去了焦点、不可见)。中间有可见、不可见生命周期。前台生命周期。

1
2
3
4
5
6
7
8
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();
}

Activity 周期图

在上图中,Activity有三个关键的循环:

整个的生命周期,从onCreate(Bundle)开始到onDestroy()结束。Activity在onCreate()设置所有的“全局”状态,在onDestory()释放所有的资源。例如:某个Activity有一个在后台运行的线程,用于从网络下载数据,则该Activity可以在onCreate()中创建线程,在onDestory()中停止线程。
可见的生命周期,从onStart()开始到onStop()结束。在这段时间,可以看到Activity在屏幕上,尽管有可能不在前台,不能和用户交互。在这两个接口之间,需要保持显示给用户的UI数据和资源等,例如:可以在onStart中注册一个IntentReceiver来监听数据变化导致UI的变动,当不再需要显示时候,可以在onStop()中注销它。onStart(),onStop()都可以被多次调用,因为Activity随时可以在可见和隐藏之间转换。
前台的生命周期,从onResume()开始到onPause()结束。在这段时间里,该Activity处于所有Activity的最前面,和用户进行交互。Activity可以经常性地在resumed和paused状态之间切换,例如:当设备准备休眠时,当一个Activity处理结果被分发时,当一个新的Intent被分发时。所以在这些接口方法中的代码应该属于非常轻量级的。

 

      1. protected void onCreate(Bundle savedInstanceState)一个 Activity 的实例被启动时调用的第一个方法。一般情况下,我们都覆盖该方法作为应用程序的一个入口点,在这里做一些初始化数据、设置用户界面等工作。大多数情况下,我们都要在这里从 xml 中加载设计好的用户界面。例如:
 setContentView(R.layout.main);

 

当然,也可从 savedInstanceState中读我们保存到存储设备中的数据,但是需要判断savedInstanceState是否为 null,因为 Activity 第一次启动时并没有数据被存贮在设备中:

 if(savedInstanceState!=null){
 savedInstanceState.get("Key");
 }

 

      1. protected void onStart()该方法在 onCreate() 方法之后被调用,或者在 Activity 从 Stop 状态转换为 Active 状态时被调用。
      2. protected void onResume()在 Activity 从 Pause 状态转换到 Active 状态时被调用。
      3. protected void onResume()在 Activity 从 Active 状态转换到 Pause 状态时被调用。
      4. protected void onStop()在 Activity 从 Active 状态转换到 Stop 状态时被调用。一般我们在这里保存 Activity 的状态信息。
      5. protected void onDestroy()在 Active 被结束时调用,它是被结束时调用的最后一个方法,在这里一般做些释放资源,清理内存等工作。
      6. 创建一个 Activity在 android 中创建一个 Activity 是很简单的事情,编写一个继承自android.app.Activity的 Java 类并在 AndroidManifest.xml声明即可。下面是一个为了研究 Activity 生命周期的一个 Activity 实例(工程源码见下载):Activity 文件:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        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,将 apk 文件安装后,系统根据这里的说明来查找读取 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”来将我们消息传递出去:

        1
         

        那么“收件人”该如何收信呢?在 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对象,将我们的数据存贮在这个 HashMap 中来进行传递。但是像上面这样的代码稍显复杂,因为 Intent 内部为我们准备好了一个 bundle,所以我们也可以使用这种更为简便的方法:

        1
        2
        3
        4
        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 来处理这些数据而不需要程序员直接操作这些文件或者考虑数据同步问题。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        // 写入 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 配置文件中可以通过 节点为一个 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 的匹配过程
        Action 匹配

        Action 是一个用户定义的字符串,用于描述一个 Android 应用程序组件,一个 Intent Filter 可以包含多个 Action。在 AndroidManifest.xml 的 Activity 定义时可以在其节点指定一个 Action 列表用于标示 Activity 所能接受的“动作”,例如:

         
         
         
        ……
         

        如果我们在启动一个 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 携带外部数据给目标组件。在 节点中,通过节点匹配外部数据。

        mimeType 属性指定携带外部数据的数据类型,scheme 指定协议,host、port、path 指定数据的位置、端口、和路径。如下:

         

        如果在 Intent Filter 中指定了这些属性,那么只有所有的属性都匹配成功时 URI 数据匹配才会成功。

        Category 类别匹配

        节点中可以为组件定义一个 Category 类别列表,当 Intent 中包含这个列表的所有项目时 Category 类别匹配才会成功。

         

        一些关于 Activity 的技巧

        锁定 Activity 运行时的屏幕方向

        Android 内置了方向感应器的支持。在 G1 中,Android 会根据 G1 所处的方向自动在竖屏和横屏间切换。但是有时我们的应用程序仅能在横屏 / 竖屏时运行,比如某些游戏,此时我们需要锁定该 Activity 运行时的屏幕方向,节点的android:screenOrientation属性可以完成该项任务,示例代码如下:

         // 竖屏 , 值为 landscape 时为横屏
        …………
         

        全屏的 Activity

        要使一个 Activity 全屏运行,可以在其 onCreate()方法中添加如下代码实现:

         // 设置全屏模式
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
         // 去除标题栏
         requestWindowFeature(Window.FEATURE_NO_TITLE);

        在 Activity 的 Title 中加入进度条

        为了更友好的用户体验,在处理一些需要花费较长时间的任务时可以使用一个进度条来提示用户“不要着急,我们正在努力的完成你交给的任务”。如下图:

        在 Activity 的标题栏中显示进度条不失为一个好办法,下面是实现代码:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        // 不明确进度条
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.main);
        setProgressBarIndeterminateVisibility(true);
         
        // 明确进度条
        requestWindowFeature(Window.FEATURE_PROGRESS);
        setContentView(R.layout.main);
        setProgress(5000);



         
      7. 【北大青鸟深圳嘉华】

评论