您的位置:首页 > 移动开发 > Android开发

Android四大组件之Activity总结

2017-11-27 23:02 471 查看

Android四大组件之Activity总结



1.基本介绍

  Activity在Android中被翻译为“活动”的意思,它是一种可以包含用户界面的组件,像活动一样组织着界面的控件给用户完成各种需求,一个应用可以包含0个或者多个Activity,但是0个Activity的应用很少很少,基本上都是那种纯在后台运行的应用才一个Activity也没有,所以Android中开发Activity是与我们打交道最多的组件,它与广播,内容提供者,服务并称Android四大组件。

1.1 基本用法

  在Android中Activity具有以下结构(此处借用书籍《Android群英传》):



  既然Activity是用户界面的组件,那么它肯定包含一个显示用户各种控件的结构,每个Activity都包含一个Window对象,在Android中Window对象通常由PhoneWindow这个类来实现的。而PhoneWindow将一个DecorView设置为整个应用窗口的根View。DecorView作为窗口界面的顶层视图,封装了一些窗口操作的通用方法。可以说,DecorView将要显示的具体内容呈现在了PhoneWindow上,这里面的所有View的监听事件,都通过WindowManageService来进行接收,并通过Activity对象来回调相应的onClickListener,其实就是在说事件分发拦截机制,请看博客:http://blog.csdn.net/clandellen/article/details/78636927。在显示上,它将屏幕分成两部分,一个是TitleView,另一个是ContentView。看到这里,大家一定看见了一个非常熟悉的布局——————ContentView,这是我们在给Activity设置布局的时候用到的方法setContentView方法对应的那个布局,这下终于知道setContentView方法给谁设置了布局了吧!而ContentView是一个ID为content的Framelayout,至于TitleView就是“标题视图”的意思,毫无疑问就是ActionBar一样的东东,所以DecorView的视图树如下所示:



  讲完上面的Activity的结构之后,我们再来看看如何创建活动,给Activity的ContentView绑定一个布局,如何注册在AndroidManifest.xml中。首先,我们来看看如何创建一个活动,创建活动的第一步就是自定义一个类去继承Activity类,可以直接继承Actiivty类,也可以继承它的各种子类,反正就是加入Activity家族。继承之后下一步就是为ContentView绑定一个布局,如何绑定呢?就是在自定义的类中重写onCreate方法,在onCreate方法中,执行setContentView方法,然后通过R.layout.XXX的方式绑定布局,示例代码如下:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.singeractivity_layout);//为ContentView绑定布局文件singeractivity_layout对应的布局

}


  onCreate方法是Activity的生命周期函数之一,onCreate是Activity要启动时执行的第一个生命周期函数,通常我们需要在onCreate方法中绑定ContentView的布局,初始化数据等。为了更好的设计我们需要的Activity,我们需要了解一下内容:

1.Android的布局种类,比如:线性布局,相对布局等

http://blog.csdn.net/ClAndEllen/article/details/78641599

2.Android中的基本控件和复杂控件,比如:基本控件TextView,Button等,复杂控件ListView,RecylerView,ViewPager,FragMent,自定义控件等

3.Activity的ActionBar,Menu如何设计。

http://blog.csdn.net/guolin_blog/article/details/18234477(ActionBar)

https://www.cnblogs.com/smyhvae/p/4133292.html(Menu)

4.Activity的生命周期,了解Activity的生命周期是非常有必要的,Activity的生命周期指的就是Activity从启动到销毁所有经历的阶段,这些阶段都一一对应着各种生命周期函数,比如:onCreate生命周期函数在Activity刚启动时执行的第一个生命周期函数。

5.Activity的启动模式,一个应用并不是只有一个Activity的,当你从一个Activity切换至另外一个Activity时,启动模式起着至关重要的作用,每次启动一个新的Activity就去在内存中新建一个Activity实例对象,如果你多次启动同一个Activity,这似乎很浪费内存空间,所以Activity的启动模式能改变这种浪费,甚至有一些笔者这里无法用简单言语说出的好处,避免浪费内存只是好处之一。

6.Activity的切换以及切换时信息的交互,Activity的切换是使用Intent来完成的,至于Activity的信息交互的方式,有很多种,比如Intent可以,广播也可以,甚至一些其他的方式,这需要我们都去了解,灵活运用。

7.Activity的上下文Context的理解,以及各种场景如何获取当前Activity的上下文。

http://blog.csdn.net/guolin_blog/article/details/47028975

  接下来我们来看看Activity的生命周期:

2.Activity的生命周期

  下面是Activity的生命周期图,我们详细来看看Activity的生命的各个阶段是怎么回事:



1.启动了一个Activity,通常是Intent来完成。启动一个Activity首先要执行的回调函数是onCreate(),通常在代码中你需要在此函数中绑定布局,绑定控件,初始化数据等做一些初始化的工作。

2.即将执行Activity的onStart()函数,执行之后Activity已经可见,但是还没有出现在前台,无法与用户进行交互。这个时候通常Activity已经在后台准备好了,但是就差执行onResume()函数出现在前台。

3.即将执行Activity的onResume()函数,执行之后Activity不止可见而且还会出现在前台,可以与用户进行交互啦。

4.由于Activity执行了onResume()函数,所以Activity出现在了前台。也就是Activity处于运行状态。

5.处于运行状态的Activity即将执行onPause()函数,什么情况下促使Activity执行onPause()方法呢?

 [1]启动了一个新的Activity

 [2]返回上一个Activity

 可以理解为当需要其他Activity,当前的Activity必须先把手头的工作暂停下来,再来把当前的界面空间交给下一个需要界面的Activity,而onPause()方法可以看作是一个转接工作的过程,因为屏幕空间只有那么一个,每次只允许一个Activity出现在前台进行工作。通常情况下onPause()函数不会被单独执行,执行完onPause()方法后会继续执行onStop()方法,执行完onStop()方法才真正意味着当前的Activity已经退出前台,存在于后台。

6.Activity即将执行onStop()函数,在“5”中已经说得很清楚了,当Activity要从前台切换至后台的时候会执行,比如:用户点击了返回键,或者用户切换至其他Activity等。

7.当前的Activity即将执行onDestory()函数,代表着这个Activity即将进入生命的终结点,这是Activity生命周期中的最后一次回调生命周期,我们可以在onDestory()函数中,进行一些回收工作
4000
和资源的释放工作,比如:广播接收器的注销工作等。

8.执行完onDestory()方法的Activity接下来面对的是被GC回收,宣告生命终结。

9.很少情况下Activity才走“9”,网上一些关于对话框弹出后Activity会走“9”的说法,经过笔者验证,在某个Activity内弹出对话框并没有走“9”,所以网上大部分这样说法的文章要么是没验证,要么直接转载的,这个例子说明,实验出真知,好了,不废话了,那么什么情况下,Activity会走“9”呢?看看下面这位博主才是真的懂得“实验出真知”的人:

http://blog.csdn.net/a872822645/article/details/62217965

10.当用户在其他的Activity或者桌面回切到这个Activity时,这个Activity就会先去执行onRestart()函数,Restart有“重新开始”的意思,然后接下来执行onStart()函数,接着执行onResume()函数进入到运行状态。

11.在“10”中讲的很清楚了。

12.高优先级的应用急需要内存,此时处于低优先级的此应用就会被kill掉。

13.用户返回原Activity。

下面来着重说明一下Activity每个生命周期函数:

onCreate():

 表示Activity正在被创建,这是Activity生命周期的第一个方法。通常我们程序员要在此函数中做初始化的工作,比如:绑定布局,控件,初始化数据等。

onStart():

 表示Activity正在被启动,这时候的Activity已经被创建好了,完全过了准备阶段,但是没有出现在前台,需要执行onResume()函数才可以进入到前台与用户进行交互。

onResume():

 表示Activitiy已经可见了,并且Activity处于运行状态,也就是Activity不止出现在了前台,而且还可以让用户点击,滑动等等操作与它进行交互。

onPause():

 表示Activity正在暂停,大多数情况下,Activity执行完onPause()函数后会继续执行onStop()函数,造成这种函数调用的原因是当前的Activity启动了另外一个Activity或者回切到上一个Activity。还有一种情况就是onPause()函数被单独执行了,并没有附带执行onStop()方法,造成这种函数调用的原因很简单,就是当前Activity里启动了类似于对话框的东东。

onStop():

 表示Activity即将停止,我们程序员应该在此函数中做一些不那么耗时的轻量级回收操作。

onRestart():

 表示Activity正在重新启动。一般情况下,一个存在于后台不可见的Activity变为可见状态,都会去执行onRestart()函数,然后会继续执行onStart()函数,onResume()函数出现在前台并且处于运行状态。

onDestory():

 表示Activity要被销毁了。这是Activity生命中的最后一个阶段,我们可以在onDestory()函数中做一些回收工作和资源释放等,比如:广播接收器的注销等。

生命周期的理解光靠这些理论的总结,肯定是记不住的,最好是长时间留心,写代码去验证。接下来,我们再来看看Activity的启动模式与Activity的切换:

3.Activity的启动模式与Activity的切换

3.1 Activity的启动模式

  Activity的启动模式有4种,分别是:standard,singleTop,singleTask和singleInstance。下面一一作介绍:

1.系统默认的启动模式:standard

  标准模式,这也是系统的默认模式。每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否存在。被创建的实例的生命周期符合典型情况下的Activity的生命周期。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity的任务栈中。比如Activity A启动了Activity B(B是标准模式),那么B就会进入到A所在的任务栈中。有个注意的地方就是当我们用ApplicationContext 去启动standard模式的Activity就会报错,这是因为standard模式的Actiivty默认会进入启动它的Activity所属的任务栈中,但是由于非Activity类型的Context(如ApplicationContext)并没有所谓的任务栈,所以这就会出现错误。解决这个问题的方法就是为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候就会为它创建一个新的任务栈,这个时候启动Activity实际上以singleTask模式启动的,读者可以自己仔细体会。

2.栈顶复用模式:singleTop

  在这种模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法被回调,通过此方法的参数我们可以取出当前请求的信息。需要注意的是,这个Activity的onCreate,onStart不会被系统调用,因为它并没有发生改变。如果新的Activity已经存在但不是位于栈顶,那么新的Activity仍然会重新重建。举个例子,假设目前栈内的情况为ABCD,其中ABCD为四个Activity,A位于栈低,D位于栈顶,这个时候假设要再次启动D,如果D的启动模式为singleTop,那么栈内的情况依然为ABCD;如果D的启动模式为standard,那么由于D被重新创建,导致栈内的情况为ABCDD。

3.栈内复用模式:singTask

  这是一种单例实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,和singleTop一样,系统也会回调其onNewIntent。具体一点,当一个具有singleTask模式的Activity请求启动后,比如Activity A,系统首先寻找任务栈中是否已存在Activity A的实例,如果已经存在,那么系统就会把A调到栈顶并调用它的onNewIntent方法,如果Activity A实例不存在,就创建A的实例并把A压入栈中。举几个栗子:

比如目前任务栈S1的情况为ABC,这个时候Activity D以singleTask模式请求启动,其所需的任务栈为S2,由于S2和D的实例均不存在,所以系统会先创建任务栈S2,然后再创建D的实例并将其投入到S2任务栈中。

另外一种情况是,假设D所需的任务栈为S1,其他情况如同上面的例子所示,那么由于S1已经存在,所以系统会直接创建D的实例并将其投入到S1。

如果D所需的任务栈为S1,并且当前任务栈S1的情况为ADBC,根据栈内复用的原则,此时D不会重新创建,系统会把D切换到栈顶并调用其onNewIntent方法,同时由于singleTask默认具有clearTop的效果,会导致栈内所有在D上面的Activity全部出栈,于是最终S1中的情况为AD。

  通过以上3个例子,你应该能比较清晰地理解singleTask的含义了。

4.单实例模式:singleInstance

  这是一种加强的singleTask模式,它除了具有singleTask模式所有的特性外,还加强了一点,那就是具有此种模式的Activity只能单独位于一个任务栈中,换句话说,比如Activity A是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。

总结

上面介绍了4种启动模式,这里需要指出一种情况,我们假设目前有2个任务栈,前台任务栈的情况为AB,而后台任务栈的情况为CD,这里假设CD的启动模式均为singleTask。现在请求启动D,那么整个后台任务栈都会被切换到后台,这个时候整个后退列表变成了ABCD。当用户按back键的时候,列表中的Activity会一一出栈,如下图1所示:



  如果不是请求的D而是请求的C,那么情况就不一样了,如下图2所示:



  如何指定活动的启动模式呢?在AndroidManifest.xml文件当注册活动的代码中去指定

比如:我要把MainActivity活动的启动模式指定为singleInstance模式



3.2 Activity的切换

  在Android中Activity的切换使用的是Intent,Intent可是一个非常重要地位的组件,它不止用来对Activity的切换,它还可以用来启动一个Activity,发送一个广播,启动或者停止一个服务,在Activity之间可以用来传递数据。对于Intent的了解,请看链接:

  使用Intent显式或者隐式切换Activity:

  假如你需要在FirstActivity切换到SecondActivity,那么你的代码应该这么写:

Intent intent = new Intent(FirstActivity.this,SecondActivity.class);//这里的FirstActivity.this就是上下文
startActivity(intent);


  代码中调用startActivity时省略了上下文Context,具体应该是context.startActivity(intent),而context就是上下文的一个引用。其实Activity中获取上下文很简单,直接在onCreate生命周期函数中执行以下代码即可获取上下文,对于Activity上下文Context的了解前面已经有讲到了,这里就不罗嗦了。

Context context = this;


  在使用Intent切换Activity的同时,将数据传递给待切换的Activity:

  Intent可以传递数据给下一个Activity,那么如何传递数据呢?其实很简单,Intent类的内部封装了专门用于Activity传递数据的方法,代码示例如下:

Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent,putExtra("next_activity_data","传递的数据");//把String类型的数据记录于intent的内部
startActivity(intent);


  既然有传递数据,那么肯定有接收数据,那么如何接收数据呢?

  你可以在SecondActivity的onCreate生命周期函数中写下下列代码:

Intent intent = getIntent();
String data = intent.getIntExtra("next_activity_data");//通过标记接收来接收数据


  你肯定会问”next_activity_data”是什么意思?其实这是一段标记,你可以理解为暗号,如果没有这个暗号,那么下一个Activity就不知道接收的是怎样的数据,这个数据来自哪个Activity,暗号和传递的数据值构成了键值对,一一对应,这样才不会让数据混乱。向下个Activity传递数据应用场景非常之多,比如:用户看新闻的时候处于新闻列表界面,当用户看到一个新闻的标题有兴趣,需要详细阅读,用户就会点击这条新闻条目,然后应用切换到新闻详细显示的界面同时,需要将新闻的信息传递给新闻详细显示的界面,从而显示对应的用户新闻列表界面点击的新闻。应用场景还有很多。

  既然可以向下个Activity传递数据,那么就肯定存在向上个Activity传递数据:

  当你需要从FirstActivity切换至SecondActivity的时候且需要SecondActivity返回某些数据的时候,你应该首先确定一个请求码和返回码,这个请求码和返回码和上面标记有着一样的效果,可以避免数据混乱的同时,可以得知当前返回的数据来自于哪里,这一切皆有设计者自己定义其值。当你在FirstActivity启动SecondActivity需要的是请求码,而你在SecondActivity返回FirstActivity需要的是返回码,我们先来看看如何在FirstActivity中写启动SecondActivity的代码,以及返回数据后的逻辑处理:

  首先,在FirstActivity中启动SecondActivity,代码是这么写的:

Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);//这里的1是请求码的意思,与onActivityResult方法中的requestCode对应


  然后,在FirstActivity中如何写返回数据后的逻辑呢?需要重写方法onActivityResult方法,代码是这么写的:

@Override
protected void  onActivityResult(int requestCode,int resultCode,Intent data){

switch(requestCode) {
case 1:
if(resultCode == RESULT_OK){//这里RESULT_OK就是返回码具体的值
String returnData = data.getStringData("data_return");//接收返回的数据
.....//接收返回的数据的逻辑处理
}
break;

}
}


  从英文很容易判断requestCode就是请求码,resultCode就是返回码,而data就是返回的Intent,它里面带有返回的数据,通过Intent的某些get方法即可获取返回的数据。

  那么在SecondActivity返回FirstActivity如何将数据返回呢?代码是这样写的:

Intent intent = new Intent();
intent.putExtra("data_return","返回的数据");
setResult(RESULT_OK,intent);//RESULT_OK就是返回码的意思
finish();


到这里Activity就总结完了,谢谢读者的耐心阅读。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: