Activity是Android的四大组件之一,可以说是android四大组件中最重要的组件之一。它负责了我们的界面显示,实际开发中我们通过setContentView(R.layout.id)设置界面显示的视图。在Android的项目结构设计中,Activity就相当于MVC设计模式中的View层。在Android的四大组件设计中,为了方便开发者进行开发使用,Android的开发者对四大组件通过生命周期进行管理,我们只需要继承Activity进行重写这些生命周期来管理和合理使用Activity。 下面我们来一起看看Android官方文档上提供的Activity的生命周期图:
通过这张图发现,Activity生命周期的主线是:onCreate()——>onStart()——>onResume()——>onPause()——>onStop()——>onDestroy()这六个流程主线。下面来分析下这六个生命周期的方法。 1、创建Activity 为了创建一个activity,我们必须创建一个Activity的子类,在我们的自定义子类中,我们需要实现这些回调方法,例如activity的create、stop、resume、destroy。方法的简介:
onCreate()方法 这个方法我们必须实现,当我们创建一个activity的时候,系统会调用这个方法。重要的是,我们必须通过setContentView()来设定activity的显示视图。(不可见)onStart()方法 在我们创建了视图之后调用,在向用户展示之前调用。然后调用onResume方法。(不可见)onResume()方法: onResume方法是activity进行可见状态,能够与用户进行交互。(可见可用)onPause()方法 当我们离开这个activity时候系统调用这个方法。注意:它不意味着activity被销毁(destroy)。暂停状态,记得小时候打游戏,按暂停,游戏界面就会停止不动,属于可见状态,但是不能用,其实原理基本类似。(可见但不可用)onStop()方法 停止状态,当一个activity被另一个activity完全覆盖的时候,它仍然保留着信息,但是已经对用户不可见。(不可见)onDestroy()方法 此时activity已经被销毁,activity至此生命周期完全结束。(销毁)通过上面的流程分析,从与用户交互的角度来说,Activity的状态分为不可见、可见可用、可见不可用、销毁。从android官方提供的文档来看,生命周期的三个阶段:
完整生命周期(entire life) activity的完整生命周期从onCreate()方法到onDestroy()方法。在开发中我们在onCreate方法中进行一些一些初始化的操作,比如控件的初始化和设置控件的监听操作。例如:如果我们有个线程在后台下载数据,它可能在onCreate()方法中创建,在onDestroy()方法中进行销毁。
可视生命周期(visible life) 可视化的生命周期从onStart()方法到onStop()方法,这段生命周期内,用户可以在屏幕上看到此activity。例如:当一个新的activity启动了,这个activity就不在显示了。在这段生命周期内,你可以管控你需要向用户展示的资源。例如:你可以在onStart()方法中注册广播接受者(BroadcastReceiver),在onStop()方法中取消注册这个广播。
前台生命周期(foreground life) 前台生命周期,此段生命周期用户可以看见交互。这段生命周期从onResume()方法到onPause()方法。在这段生命周期内,这个activity在所有的activities的前面。当这个设备进入到休眠状态或当一个对话框出现的时候调用onPause()方法。由于在这之间的生命周期切换非常频繁,所以在这段生命周期内处理的逻辑处理代码要轻量级,避免来回切换让用户等待时间太久。
在实际的开发中,我们根据activity的生命周期来实现我们的逻辑处理。通常在开发中,在onCreate()方法中进行一些变量的初始化工作,包括变量的初始化、控件的初始化、控件设置监听等。当一个activity由于失去焦点时再次重新获取焦点调用onResume方法。在onResume()方法中我们可以处理一些比如界面的更新操作。
下面我们通过实例来验证:
public class MainActivity extends Activity { private static final String TAG = "ActivityLife"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG,"onCreate"); } @Override protected void onStart() { super.onStart(); Log.d(TAG, "onStart"); } @Override protected void onStop() { super.onStop(); Log.d(TAG, "onStop"); } @Override protected void onResume() { super.onResume(); Log.d(TAG, "onResume"); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause"); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); } }(1)、启动activity,查看日志文件: 09-01 14:32:05.850 ﹕ onCreate 09-01 14:32:05.850 ﹕ onStart 09-01 14:32:05.850 ﹕ onResume 通过上面的方法分析,我们启动activity,activity获取焦点展现在我们的面前。 (2)、通过按钮进行activity的跳转,但是没有finish(): 09-01 15:03:59.590 ﹕ onCreate 09-01 15:03:59.590 ﹕ onStart 09-01 15:03:59.590 ﹕ onResume 09-01 15:04:23.546 ﹕ onPause 09-01 15:04:23.550 ﹕ SecondActivity:onCreate 09-01 15:04:23.550 ﹕ SecondActivity:onStart 09-01 15:04:23.550 ﹕ SecondActivity:onResume 09-01 15:04:24.130 ﹕ onStop 通过分析发现,我们的mainActivity在SecondActivity界面获取到焦点后执行的onStop()方法。界面失去焦点后,OnPause()方法后。当我们执行finish方法后,就会在onStop方法执行后执行onDesdroy方法。 (3)、按Home键,执行顺序 09-01 15:15:04.262 ﹕ onPause 09-01 15:15:04.942 ﹕ onStop (4)、横竖屏切换,相当于activity进行重新创建。所以声明周期会走正常创建的流程,一般在实际开发中,我们通过设定android:screenOrientation属性来设置是否允许横竖屏切换。
1、首先在manifest配置文件中进行声明:在application节点下添加activity节点配置。
<manifest ... > <application ... > <activity android:name=".ExampleActivity" /> ... </application ... > ... </manifest >activity子节点下面有很多属性配置这个activity,这么多属性中只有android:name是唯一必须要设置的,它确定了我们的activity是哪个类。所以一旦应用发布了,就不要去改变这个名称,不然会引起一起应用bug。更多的属性配置参照我的这篇博客。 2、使用intent filter 通过使用intent-filter可以声明这个组件的工作方法。我们知道,当我们创建一个应用的时候,系统会自动给我们创建好一个主activity的配置。如下:
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>在这段配置中,我们发现节点配置的main,说明这是我们应用程序的入口。的属性值为LAUNCHER标识这是应用程序的启动界面。如果你打算你的应用只供自身调用不允许别的应用程序使用,你不需要设置更多的activity,只要设置一个activity拥有main的动作和Launcher的分类就可以。然后,如果你希望你的activity能够响应不同应用发送的intent,你必须为你的activity定义额外的intent-filter项。例如:为你所有响应的各项,你必须包含一个,并设置它的和元素或者元素节点,这些元素识别intent的类型并响应。
在android系统中,我们通过Intent(意图)进行数据的传递或进行activity的跳转。在android系统中存在两种启动方式。 1、显示启动 何为显示启动,就是在创建Intent的时指定要启动的activity的类。所以前提是我们已经知道Activity的类名称,这就运用在我们在开发app中进行activity的跳转。
Intent intent = new Intent(MainActivity.this,SecondActivity.class); startActivity(intent);2、隐式启动 android系统给我们提供了许多服务,如打电话、发短信。但是在我们的应用中我们不知道具体的activity类名称,此时我们就需要用到隐式的activity启动方法。
//打电话 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:555-2368")); startActivity(intent); //发短信 Intent intent=new Intent(); intent.setAction("android.intent.action.SEND"); intent.setData(Uri.parse("mms:110")); intent.addCategory(Intent.CATEGORY_DEFAULT); startActivity(intent); //打开网页 Intent intent=new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.baidu.com")); startActivity(intent);android系统中对activity的启动模式设立了四种启动模式,分别是:standard、singleTop、singleTask、singleInstance这四种启动模式。在学习activity的启动模式之前,我们先了解下android中的任务栈的概念。如果我们有一定数据结构基础,说到‘栈’就知道它的特点:先进后出。知道这些后,我们在说android中是如何安排众多activity——通过任务栈来‘装’activity。如下图:
通过这张图,我们可以看到android系统将activity按照先后顺序放入栈中进行管理。当我们点击返回键或执行finish方法就是从栈中退出activity。 在实际开发中,我们经常会遇到这种情况,我们从activity1——>activity2,然后执行完activity2——>activity1这种循环跳转,我们就会有这种疑惑,这里的activity1连续使用,系统是重新创建的activity1的实例还是复用已经创建存在的实例呢?这里就涉及到我们的activity的启动模式涉及。下面我们详细说说这四种启动模式:
standard(默认的模式) 在创建一个activity的时候,系统默认的启动模式。在这种启动模式下,每次启动一个activity就创建一个实例放到任务栈中。所以我们对于activity不执行finish方法,就会存在多个activity的实例。singleTop(单栈顶模式) 如果一个activity实例已经存在当前任务栈的顶部,系统通过onNewIntent方法将intent发送到这个实例,而不是创建一个新的实例。singleTask(单任务模式) 如果一个activity已经在任务栈中存在,我们再次启动该activity就不需要重新创建实例。系统会将该activity实例上面的activity实例执行出栈操作,将此activity推至栈顶。singleInstance(单例模式) 如果应用1的任务栈中创建了MainActivity实例,如果应用2也要激活MainActivity,则不需要创建,两应用共享该Activity实例;说完了基本概念,我们通过简单的实例验证下: 我使用两个activity,使他们之间相互跳转。先来看下代码。 MainActivity代码:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_go = (Button)findViewById(R.id.btn_go); btn_go.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this,SecondActivity.class); startActivity(intent); } }); }SecondActivity代码:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.secondlayout); Button btn_goMain = (Button)findViewById(R.id.btn_goMain); btn_goMain.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(SecondActivity.this,MainActivity.class); startActivity(intent); } }); }(1)、将两个activity的启动模式设置为standard模式。通过android:launchMode进行设置 ,如下:
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" android:launchMode="standard"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SecondActivity" android:launchMode="standard"/> </application>我们先构造几个activity的实例,放到任务栈中。操作顺序: MainActivity->SecondActivity->MainActivity。 我们通过截图看看我们按几次返回键退出应用:
!standard模式
通过截图我们看以看到,我们点击了多次才退出应用,这说明我们在跳转的过程中新建了多个activity的实例。
(2)singleTop模式, 这种模式下,比如我们栈中有A->B->C->D,此时D在栈的顶部,我们再次进入D,如果采用standard模式,则栈中就有A->B->C->D->D,singleTop模式下就不会重新创建新的实例。A->B->C->D 我们将SecondActivity设置为singleTop模式,查看运行截图:
(3)singleTask模式: 直接上运行截图,我们设置MainActivity为singleTask,我们点击退出,直接退出应用。