来源: [转载]Android四大组件之Activity详解 – caobotao – 博客园
.Activity的本质
Activity是Android提供的四大组件之一,是进行Android开发 必不可少的组件.Activity是一个界面的载体,可以把它与html页面进行类比,html页面由各种各样的标签组成,而Activity则可以由各 种控件组成.然而Activity也并不是那么简单.查看Activity类的源码我们就可以看到,这个类大概有六千多行代码,说明Android对 Activity的处理是相当复杂的.不过我们平时进行开发的时候不需要了解到那么深入的地步,因为我们可以根据Activity中提供的方法快速的开 发,Activity生命周期中涉及到七个回调方法.
.Activity的生命周期
Android官方文档给出的Activity生命周期图
当打开一个Activity的时候,会调用这个Activity的 onCreate()方法,接着调用onStart()方法,然后调用onResume()方法.当onStart()方法执行之后,我们就可以看到这个 Activity界面了.下面通过代码对单个Activity生命周期做进一步的解释.
MainActivity.java
package com.example.caobotao.activitylifecircle; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("info","MainActivity onCreate()"); } @Override protected void onStart() { super.onStart(); Log.i("info","MainActivity onStart()"); } @Override protected void onResume() { super.onResume(); Log.i("info","MainActivity onResume()"); } @Override protected void onPause() { super.onPause(); Log.i("info", "MainActivity onPause()"); } @Override protected void onStop() { super.onStop(); Log.i("info", "MainActivity onStop()"); } @Override protected void onDestroy() { super.onDestroy(); Log.i("info","MainActivity onDestroy()"); } @Override protected void onRestart() { super.onRestart(); Log.i("info","MainActivity onRestart()"); } }
运行项目后,Logcat输出:
11-24 20:00:49.160 20104-20104/com.example.caobotao.activitylifecircle I/info: MainActivity onCreate() 11-24 20:00:49.170 20104-20104/com.example.caobotao.activitylifecircle I/info: MainActivity onStart() 11-24 20:00:49.170 20104-20104/com.example.caobotao.activitylifecircle I/info: MainActivity onResume()
点击返回键,Logcat输出:
11-24 20:05:15.370 20104-20104/com.example.caobotao.activitylifecircle I/info: MainActivity onStop() 11-24 20:05:15.370 20104-20104/com.example.caobotao.activitylifecircle I/info: MainActivity onDestroy()
下面简单讲一下Activity生命周期中每个函数的作用:
onCreate() :
当Activity第一次被创建的时候调用此方法.一般在此方法中进行控件的声明,添加事件等初始化工作.
onStart():
当Activity被显示到屏幕上的时候调用此方法.
onResume():
当此Activity能够被操作之前,也就是能够获得用户的焦点之前调用此方法.
onRestart():
当Activity被停止后又被再次启动之前调用此方法.接着将调用onStart()方法.
onPause():
当第一个Activity通过Intent启动第二个Activity的时候,将 调用第一个Activity的onPause()方法.然后调用第二个Activity的 onCreate(),onStart(),onResume()方法,接着调用第一个Activity的onStop()方法.如果Activity重 新获得焦点,则将调用onResume()方法;如果此Activity进入用户不可见状态,那么将调用onStop()方法.
onStop():
当第一个Activity被第二个Activity完全覆盖,或者被销毁的时候回调用此方法.如果此Activity还会与用户进行交互,将调用onRestart方法();如果此Activity将被销毁,那么将调用onDestroy()方法.
onDestroy():
Activity被销毁之前调用此方法.或者是调用finish()方法结束Activity的时候调用此方法.可以在此方法中进行收尾工作,比如释放资源等.
(注意:重写某个Activity的这些回调方法的时候需要首先在第一行调用基类Activity的相应的回调方法.比如super.onCreate(),super.onStart()等等.)
接下来了解一下多个Activity交互中的生命周期.在第一个Activity中添加一个按钮,用于启动第二个Activity.
AActivity.java
package com.example.caobotao.activitylifecircle; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; public class AActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("info","AActivity onCreate()"); findViewById(R.id.btnStartBAty).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(AActivity.this,BActivity.class)); } }); } @Override protected void onStart() { super.onStart(); Log.i("info","AActivity onStart()"); } @Override protected void onResume() { super.onResume(); Log.i("info","AActivity onResume()"); } @Override protected void onPause() { super.onPause(); Log.i("info", "AActivity onPause()"); } @Override protected void onStop() { super.onStop(); Log.i("info", "AActivity onStop()"); } @Override protected void onDestroy() { super.onDestroy(); Log.i("info","AActivity onDestroy()"); } @Override protected void onRestart() { super.onRestart(); Log.i("info","AActivity onRestart()"); } }
BActivity.java
package com.example.caobotao.activitylifecircle; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; public class BActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_baty); Log.i("info","BActivity oncreate()"); } @Override protected void onStart() { super.onStart(); Log.i("info","BActivity onStart()"); } @Override protected void onResume() { super.onResume(); Log.i("info","BActivity onResume()"); } @Override protected void onStop() { super.onStop(); Log.i("info","BActivity onStop()"); } @Override protected void onDestroy() { super.onDestroy(); Log.i("info", "BActivity onDestroy()"); } @Override protected void onRestart() { super.onRestart(); Log.i("info","BActivity onRestart()"); } }
运行项目后,Logcat输出:
11-26 21:14:38.960 6208-6208/com.example.caobotao.activitylifecircle I/info: AActivity onCreate() 11-26 21:14:38.970 6208-6208/com.example.caobotao.activitylifecircle I/info: AActivity onStart() 11-26 21:14:38.970 6208-6208/com.example.caobotao.activitylifecircle I/info: AActivity onResume()
点击按钮打开BActivity后,Logcat输出:
11-26 21:14:42.050 6208-6208/com.example.caobotao.activitylifecircle I/info: AActivity onPause() 11-26 21:14:42.080 6208-6208/com.example.caobotao.activitylifecircle I/info: BActivity oncreate() 11-26 21:14:42.090 6208-6208/com.example.caobotao.activitylifecircle I/info: BActivity onstart() 11-26 21:14:42.090 6208-6208/com.example.caobotao.activitylifecircle I/info: BActivity onresume() 11-26 21:14:45.750 6208-6208/com.example.caobotao.activitylifecircle I/info: AActivity onstop()
然后点击BACK键,Logcat输出:
11-26 21:20:38.650 6208-6208/com.example.caobotao.activitylifecircle I/info: BActivity onPause() 11-26 21:20:38.970 6208-6208/com.example.caobotao.activitylifecircle I/info: AActivity onRestart() 11-26 21:20:38.970 6208-6208/com.example.caobotao.activitylifecircle I/info: AActivity onStart() 11-26 21:20:38.970 6208-6208/com.example.caobotao.activitylifecircle I/info: AActivity onResume() 11-26 21:20:41.710 6208-6208/com.example.caobotao.activitylifecircle I/info: BActivity onStop() 11-26 21:20:41.710 6208-6208/com.example.caobotao.activitylifecircle I/info: BActivity onDestroy()
可以看出,当启动第二个Activity时,总是先调用第一个Activity的 onPause()方法,然后如果第二个Activity是第一次创建的话,则再调用第二个Activity的onCreate()方法,否则调用第二个 Activity的onRestart()方法,接着调用onStart(),onResume()方法.
.Activity生命周期交互设计思想
到这里,大家可能会有些疑问,谷歌为什么要这样设计呢?如:
1.当从第一个Activity启动第二个Activity的时候,为什么先调用第一个Activity的onPause()方法,然后再调用第二个Activity的onCreate()等方法呢?
解释:假如有这样一个情况,你正在使用APP听音乐,突然来了一个电话,那么当然 需要先暂停音乐,然后进行电话的处理。所以这就是onPause()方法的作用:可以用来保存当前的各种信息.可以在这个APP的onPause()方法 中实现暂停音乐的逻辑,然后再处理电话的业务处理.
2.当从第一个Activity启动第二个Activity的时候,为什么第一个Activity的onStop()方法是调用完第二个Activity的系列方法后才调用呢,为什么不在第一个Activity的onPause()方法之后就调用呢?
解释:这是谷歌对安全方面的一个考虑.假如先调用第一个Activity的 onStop()方法,那么此时第一个Activity将不可见,如果接下来调用第二个Activity的一系列创建方法失败了,那么就会导致这两个 Activity都没显示在屏幕上,就会出现黑屏等不友好界面.如果是调用完第二个Activity一系列创建方法后,再调用第一个Activity的 onStop()方法,就会避免这种情况的发生.
.Activity生命周期的应用场景
讲了这么多,大家可能会问,Activity生命周期到底实际中怎么使用.下面通 过实例来做简单的运用.在AActivity中进行音乐的播放,当点击按钮打开BActivity后,音乐需要暂停,然后点击BACK键返回到 AActivity后音乐继续播放.这就需要在AActivity中的onPause()方法中进行音乐的暂停操作,以及暂停时音乐播放位置的记录.在 AActivity中的onResume()方法中实现重新返回前台时继续音乐的播放.
AActivity.java
package com.example.caobotao.activitylifecircle; import android.app.Activity; import android.content.Intent; import android.media.MediaPlayer; import android.os.Bundle; import android.util.Log; import android.view.View; public class AActivity extends Activity { private MediaPlayer mediaPlayer; private int position; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mediaPlayer = MediaPlayer.create(this,R.raw.song); mediaPlayer.start(); Log.i("info","AActivity onCreate()"); findViewById(R.id.btnStartBAty).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(AActivity.this,BActivity.class)); } }); } @Override protected void onStart() { super.onStart(); Log.i("info","AActivity onStart()"); } @Override protected void onResume() { super.onResume(); //如果播放的位置不是0 if (position != 0){ mediaPlayer.seekTo(position);//获取播放的位置 mediaPlayer.start();//开始播放 } Log.i("info","AActivity onResume()"); } @Override protected void onPause() { super.onPause(); //如果播放器正在播放 if (mediaPlayer.isPlaying()){ mediaPlayer.pause();//暂停播放 position = mediaPlayer.getCurrentPosition();//获得暂停时播放的位置 } Log.i("info", "AActivity onPause()"); } @Override protected void onStop() { super.onStop(); Log.i("info", "AActivity onStop()"); } @Override protected void onDestroy() { super.onDestroy(); Log.i("info","AActivity onDestroy()"); } @Override protected void onRestart() { super.onRestart(); Log.i("info","AActivity onRestart()"); } }
BActivity.java
package com.example.caobotao.activitylifecircle; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; public class BActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_baty); Log.i("info","BActivity onCreate()"); } @Override protected void onStart() { super.onStart(); Log.i("info","BActivity onStart()"); } @Override protected void onResume() { super.onResume(); Log.i("info","BActivity onResume()"); } @Override protected void onPause() { super.onPause(); Log.i("info","BActivity onPause()"); } @Override protected void onStop() { super.onStop(); Log.i("info","BActivity onStop()"); } @Override protected void onDestroy() { super.onDestroy(); Log.i("info", "BActivity onDestroy()"); } @Override protected void onRestart() { super.onRestart(); Log.i("info","BActivity onRestart()"); } }
.启动系统中常见的Activity
系统给我们提供了很多常用的Activity,可以用来打开浏览器,打开发短信界面,打开相册界面,打开拨号界面等等.
打开浏览器网页:
Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.baidu.com")); startActivity(intent);
打开相册:
Intent intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivity(intent);
打开发送短信界面:
Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT,"Hello World !"); startActivity(intent);
打开拨号界面:
Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("tel:110")); startActivity(intent);
.Activity之间的数据交互
我们可以使用Intent对象进行数据的传递.Intent重载了很多putExtra()方法,囊括了JAVA八大基本类型及其数组类型等.
Activity1.java
Activity2.java
Intent对象还有一个putExtras(Bundle bundle)方法,bundle的意思为一捆,就是把需要传递的数据打成一捆进行传递.下面利用Bundle实现上面的示例,效果一样.
Activity1.java
Activity2.java
在实际开发中,可能需要传递的数据比较多,不仅有姓名,年龄,可能还有性别,学校,爱好等等.根据面向对象的思想,我们应该想到把这些信息封装成一个java实体类,以达到更好的复用性,耦合性等目的,然后使用Bundle对象的putSerializable()方法将此需要传递的对象传递出去,在另一个Activity中用Intent对象的getSerializableExtra()方法进行接收.
Person.java
Activity1.java
Activity2.java
.Task与Back Stack(引自官方文档)
task 是一系列被操作的 activity 的集合,用户进行操作时将与这些 activity 进行交互。 这些 activity 按照启动顺序排队存入一个栈(即“back stack”)。我们知道栈是一个后进先出的数据结构,在一个task中,每打开一个新的activity,就会将其压入栈顶的位置;每次点击Back键,栈顶的activity就会被移除.
大部分 task 都启动自 Home 屏幕。当用户触摸 application launcher 中的图标(或 Home 屏幕上的快捷图标)时,应用程序的 task 就进入前台。 如果该应用不存在 task(最近没有使用过此应用),则会新建一个 task,该应用的“main”activity 作为栈的根 activity 被打开。
当用户返回到 home屏幕执行另一个 task 时,一个 task 被移动到后台执行,此时它的返回栈(back stack)也被保存在后台, 同时 android 为新 task 创建一个新的返回栈(back stack),当它被再次运行从而返回前台时,它的返回栈(back stack)被移到前台,并恢复其之前执行的activity,如下图所示。 如果后台有太多运行 task ,系统将会杀死一些 task 释放内存。
如果当前 activity 启动了另一个 activity,则新的 activity 被压入栈顶并获得焦点。 前一个 activity 仍保存在栈中,但是被停止。activity 停止时,系统会保存用户界面的当前状态。 当用户按下返回键,则当前 activity 将从栈顶弹出(被销毁),前一个 activity 将被恢复(之前的用户界面状态被恢复)。 activity 在栈中的顺序永远不会改变,只会压入和弹出——被当前 activity 启动时压入栈顶,用户用返回键离开时弹出。 这样,back stack 以“后进先出”的方式运行。下图以时间线的方式展示了多个 activity 切换时对应当前时间点的 back stack 状态。
图: task 中的每个新 activity 都会相应在 back stack 中增加一项。当用户按下返回键时,
当前 activity 被销毁,前一个 activity 被恢复。
如果用户不停地按下返回键,则栈中每个 activity 都会依次弹出,并显示前一个 activity,直至用户回到 Home 屏幕(或者任一启动该 task 的 activity)。 当所有 activity 都从栈中弹出后, task 就此消失。
.Activity启动模式(引自官方文档)
在 manifest 文件中声明 activity 时,你可以利用activity元素的launchMode属性来设定 activity 与 task 的关系。
launchMode 属性指明了 activity 启动 task 的方式。 launchMode 属性可设为四种启动模式:
- standard(默认模式):
- 默认值。系统在启动 activity 的 task 中创建一个新的 activity 实例,并把 intent 传送路径指向它。该 activity 可以被实例化多次,各个实例可以属于不同的 task,一个 task 中也可以存在多个实例。
singleTop:
- 如果 activity 已经存在一个实例并位于当前 task 的栈顶,则系统会调用已有实例的onNewIntent()方法把 intent 传递给已有实例,而不是创建一个新的 activity 实例。activity 可以被实例化多次,各个实例可以属于不同的 task,一个 task 中可以存在多个实例(但仅当 back stack 顶的 activity 实例不是该 activity 的)。
- 比如,假定 task 的 back stack 中包含了根 activity A 和 activities B、C、D(顺序是 A-B-C-D;D 在栈顶)。
- 这时过来一个启动 D 的 intent。如果 D 的启动模式是默认的”standard”,则会启动一个新的实例,栈内容变为 A-B-C-D-D。
- 但是,如果 D 的启动模式是”singleTop”,则已有的 D 实例会通过onNewIntent():接收这个 intent,因为该实例位于栈顶——栈中内容仍然维持 A-B-C-D 不变。当然,如果 intent 是要启动 B 的,则 B 的一个新实例还是会加入栈中,即使 B 的启动模式是”singleTop”也是如此。
注意: 一个 activity 的新实例创建完毕后,用户可以按回退键返回前一个 activity。 但是当 activity 已有实例正在处理刚到达的 intent 时,用户无法用回退键回到 onNewIntent() 中 intent 到来之前的 activity 状态。
- singleTask:
- 系统将创建一个新的 task,并把 activity 实例作为根放入其中。但是,如果 activity 已经在其它 task 中存在实例,则系统会通过调用其实例的onNewIntent() 方法把 intent 传给已有实例,而不是再创建一个新实例。 此 activity 同一时刻只能存在一个实例。
注意: 虽然 activity 启动了一个新的 task,但用户仍然可以用回退键返回前一个 activity。
singleInstance:
- 除了系统不会把其它 activity 放入当前实例所在的 task 之外,其它均与”singleTask”相同。activity 总是它所在 task 的唯一成员;它所启动的任何 activity 都会放入其它 task 中。
举个例子,Android 的浏览器应用就把 web 浏览器 activity 声明为总是在它自己独立的 task 中打开——把 activity设为singleTask模式。 这意味着,如果你的应用提交 intent 来打开 Android 的浏览器,则其 activity 不会被放入你的应用所在的 task 中。 取而代之的是,或是为浏览器启动一个新的 task;或是浏览器已经在后台运行,只要把 task 调入前台来处理新 intent 即可。
无论 activity 是在一个新的 task 中启动,还是位于其它已有的 task 中,用户总是可以用回退键返回到前一个 activity 中。 但是,如果你启动了一个启动模式设为singleTask的 activity,且有一个后台 task 中已存在实例的话,则这个后台 task 就会整个转到前台。 这时,当前的 back stack 就包含了这个转入前台的 task 中所有的 activity,位置是在栈顶。下图就展示了这种场景。
图 . 启动模式为“singleTask”的 activity 如何加入 back stack 的示意图。 如果 activity 已经是在后台 task 中并带有
自己的 back stack,则整个后台 back stack 都会转入前台,并放入当前 task 的栈顶。