首先,Activity是Android系统中的四大组件之一,可以用于显示View。Activity是一个与用记交互的系统模块,几乎所有的 Activity都是和用户进行交互的,但是如果这样就能说Activity主要是用来显示View就不太正确了。它不仅显示数据,也传输数据,很多程序中使用到MVC模式,
M(Model 模型):Model是应用程序的主体部分,所有的业务逻辑都应该写在这里,在Android中Model层与JavaEE中的变化不大,如:对数据库的操 作,对网络等的操作都放在该层(但不是说它们都放在同一个包中,可以分开放,但它们统称为Model层)。
V(View 视图):是应用程序中负责生成用户界面的部分,也是在整个MVC架构中用户唯一可以看到的一层,接收用户输入,显示处理结果;在Android应用中一般 采用XML文件里德界面的描述,使用的时候可以非常方便的引入,当然也可以使用JavaScript+Html等方式作为View。
C(Controller控制层)android的控制层的重任就要落在众多的activity的肩上了,所以在这里就要建议大家不要在activity中写太多的代码,尽量能过activity交割Model业务逻辑层处理。
在Android中Activity主要是用来做控制的,它可以选择要 显示的View,也可以从View中获取数据然后把数据传给Model层进行处理,最后再来显示出处理结果。
也有一种新的MVP模式:
模型(Model):负责处理数据的加载或者存储,比如从网络或本地数据库获取数据等;
视图(View):负责界面数据的展示,与用户进行交互;
主持人(Presenter):相当于协调者,是模型与视图之间的桥梁,将模型与视图分离开来。
其中的主要内容这里不介绍,这里告诉大家,不仅仅需要学习MVC模式,也需要学习MVP模式,这里特别不建议大家这样写:将所有的事情都交给Activity来完成,比如网络请求,业务逻辑处理,这样造成了Activity特别臃肿,一个大的Activity,在后期很难维护。MVC如果用不好,就会将所有的信息都放在Activity上。protected void onCreate(Bundle icicle);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
要想了解Activity,那么就必须要清楚Activity的生命周期,图片是最生动的,如下图:
上面一张图有可能有些模糊,那请看下面这张图():
整个Activity周期,activity创建时调用Oncreate(),这个时候调用setContentView(View)函数,加载xml布局文件。调用OnStart()方法,Activity显示在屏幕上,这个时候还不能与用户交互,调用OnResume()方法,用户与Activity进行交互,当前Activity被切换的时候,这个时候调用OnPause()方法,在该方法中保存一些持久数据和释放占用的资源,这个时候,屏幕还是可见,调用onStop()方法,Activity切换到后台,用户不可见。onDestroy()activity终止。
Activity的响应时间
当前Activity所在的线程为主线程,它的响应时间为5秒,如果在当前运行的Activity中进行耗时的操作且响应时间起过5秒,那么程序就会报ANR错误。所以,这也是不建议在Activity中写太多复杂代码的原因之一。
当然,有些代码只能写在Activity中,不然就运行不了(它们不是生命周期方法),比如你想要获得android系统或者硬件一的些信息,就必须在Activity中写出来,如果单独写一个工具类获得不了。
Activity栈
Activity栈保存了已经启动并且还没有终止的所有的Activity,并且我们知道栈是遵从“后进先出”的规则,那么Activity栈同样也遵从这样的规则。
Activity 的状态与其在Activity栈的位置有着密切的关系。不仅如此,Android系统在资源不足时,也是通过Activity栈来选择哪些 Activity是可以被终止的,一般来讲,Activity系统会优先选择终止处于目前是停止状态并且比较靠近Activity栈底的 Activity。
1. Activity的4种状态
Activity的生命周期指Activity从启动到销毁的过程,Activity有4种状态:
(1)活动(Active)状态:这时候Activity处于栈顶,且是可见的,有焦点的,能够接收用户输入前 景Activity。Runtime将试图不惜一切代价保持它活着,甚至杀死其他Activity以确保它有它所需的资源。当另一个Activity变成Active时,当前 的将变成Paused状态。
(2)暂停(Paused)状态:在 某些情况下,你的Activity是可见的,但没有焦 点,在这时候,Actvity处于Paused状态。例如,如果有一个透明或非全屏幕上的Activity在你的Actvity上面,你的 Activity将。当处于Paused状态时,该Actvity仍被认为是Active的,但是它不接受用户输入事件。在极端情况下,Runtime将 杀死Paused Activity,以进一步回收资源。当一个Actvity完全被遮住时,它将进入Stopped状态。
(3)停止(Stopped)状态:当Activity是不可见的时,Activity处于Stopped状态。Activity将继续保留在内存中保持当前的所有状态和成员信息,假 设系统别的地方需要内存的话,这时它是被回收对象的主要候选。当Activity处于Stopped状态时,一定要保存当前数据和当前的UI状态,否则一 旦Activity退出或关闭时,当前的数据和UI状态就丢失了。
(4)非活动(Inactive)状态:Activity被杀掉以后或者被启动以前,处于Inactive状态。这时Activity已被移除从Activity堆栈中,需要重新启动才可以显示和使用。
1) 启动Activity:onCreate()->onStart()->onResume()->Activityis running
2) 按back键返回:onPause()->onStop()->onDestroy() 再次启动时:onCreate()->onStart()->onResume()->Activityis running
3). 按home键返回:onPause()->onStop() 再次启动时:onRestart()->onStart()->onResume()->Activity isrunning
4) 切换到别的Activity(当前Activity不finish),或者采用这个,启动程序进入Activity,按Home键进入桌面,然后长按Home建点击该应用重新进入Activity:onPause()->onStop() 再次启动时:onRestart()->onStart()->onResume()->Activityis running
5) 切换到别的Activity(当前Activity finish):onPause()->onStop()->onDestroy() 再次启动时:onCreate()->onStart()->onResume()->Activity isrunning
6)然后按挂机键,进入锁屏界面,然后从锁屏界面返回Activity:onPause()->onResume()
7)切换到另一个Activity对话框界面,然后按返回键返回原来的Activity:onPause()->onResume()
8)启动本Activity中创建的对话框(弹出Toast和AlertDialog),按返回键从Dialog返回:Activity的状态始终未变
9)无论现在是onPause状态还是onStop状态,当系统的内存不足时,都会将该Activity杀死,当再次进入该Activity重新创建。这意味着,如果发生这种情况,可能我们的onDestroy(如果在停止状态被杀死),甚至是onStop都没有得到执行(如果在暂停状态被杀死),因此,一些重要的数据和状态,需要在这种情况下也得到保存,Google为我们专门提供了一个回调函数,就是onSaveInstanceState(Bundle),通过该函数,可以将这些重要的数据在销毁前进行保存,然后再onCreate时重新读
10)横竖屏切换时候activity的生命周期:
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
11)当在MainActivity中按back键,退出时,或者在代码中调用finish(),finishActivity()方法,最终就会走到onDestory()。
tips:
在多数情况下,你是不需要显式地调用finish…()方法去销毁一个activity。在将要讨论到的activity生命周期里,你可以知道,Android系统会为你管理activity的生命周期,所以你并不需要显式销毁activity(即调用finish类方法)。显式地调用finish类方法,会对用户的体验产生不利的影响,除非你确实是不希望用户返回到此activity(界面),才去显式调用finish类方法。
特殊函数
1. startActivityForResult / onActivityResult / setResult 函数组合
提到这类函数组合,相信只要有过一段时间Android开发的来说都很熟悉了,此函数组合主要用于如下场景:用户在A Activity上点击某个按钮,跳转到B Activity,然后用户在B Activity上进行一些具体的操作,待操作完成后返回到A Activity,同时常常将B Activity中操作的一些数据返回到A Activity中。
再如上场景中,A -> B 需要通过startActivityForResult()方式打开。具体方式如下:
1 button.setOnClickListener(new View.OnClickListener() {
2 @Override
3 public void onClick(View v) {
4 Intent intent = new Intent(AActivity.this, BActivity.class);
5 startActivityForResult(intent, 1);
6 }
7 });
其中,startActivityForResult第一个参数为Intent,因此,对于需要传递额外参数时,可以通过Intent直接传递。其中Bundle为可选参数。第二个参数为requestCode,即业务请求码。
B Activity中,在处理完或相应完用户操作后,自身结束前,需要通过setResult将数据回传给A。
1 btnClose.setOnClickListener(new View.OnClickListener() {
2 public void onClick(View v) {
3
4 // 需要返回的数据存入到intent中
5 Intent intent = new Intent();
6 intent.putExtra("name", "corn");
7
8 //设置返回数据
9 setResult(RESULT_OK, intent);
10
11 //关闭Activity
12 finish();
13 }
14 });
接下来A接手B回传的数据。
1 @Override
2 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
3 String name;
4 // 取得B回传的数据
5 if(resultCode == RESULT_OK ){
6 name = intent.getStringExtra("name");
7 } else if(resultCode == RESULT_CANCELED){
8 // ...
9 }
10 }
此函数组合中,需要注意如下问题:
1.根据项目的实际需要进行定义,特别需要注意的是,requestCode必须 >= 0,否则此类效果失效,其效果将变成startActivity()效果;
2.resultCode表示B中处理后的结果状态,系统内部定义了RESULT_OK、RESULT_CANCELED和RESULT_FIRST_USER三种状态。当然,自己可以定义成任何int型标识状态。
3.有时在复杂的业务逻辑中,可能存在A startActivityForResult 到B,同时C也startActivityForResult 到B,且requestCode可能相同(以表示同意业务请求),这时可能需要在B中针对性的判断此请求来源(来自于A还是C)。此时,可以通过intent传参形式。相信大家都比较熟悉,其实Activity类中也提供了相应的函数可以获取到来源Activity的类型函数:getCallingActivity()。但需要注意此函数仅针对startActivityForResult有效,返回的结果中包含完成包名。
4.A中回调函数调用时机需要注意,其调用发生在B的onPause之后,A的onRestart之前(如果B完成遮住了A),且必然在onResume之前。
5.此函数组合针对B的启动模式为singleTask或singInstance将会失效。此时,onActivityResult将在A的onpause之后直接回调,且resultCode为RESULT_CANCELED。
2.moveTaskToBack
如《Android总结篇系列:Activity生命周期》一文中有提到的,模拟现在的主流应用最后按Back键时不是强制退出应用或直接结束根Activity,而是采取类Home键效果,此时可以直接通过此函数实现,非常实用。
1 @Override
2 public void onBackPressed() {
3 moveTaskToBack(true);
4 }
此方法直接将当前Activity所在的Task移到后台,同时保留activity顺序和状态。
3.onNewIntent调用时机
onNewIntent只有在以下场景才会回调:当前通过Intent方式启动的Activity不是重新完整新建实例,而是复用之前已经存在的实例(如被设置了singleTop启动模式,或FLAG_ACTIVITY_SINGLE_TOP intent flags或设置了Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP等,以此类推,被设置了singleTask或single。此时都会执行到onNewIntent)。onNewIntent调用后,将继续回调onRestart,onResume...
4.onSaveInstanceState / onRestoreInstanceState调用时机
onSaveInstanceState调用时机:当Activity变得“容易”被系统销毁时,onSaveInstanceState即被回调,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
注意上面的双引号,何为“容易”?言下之意就是该activity还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?
1.当用户按下HOME键时;
2.长按HOME键,选择运行其他的程序时;
3.按下电源按键(关闭屏幕显示)时;
4.从activity A中启动一个新的activity时;
5.屏幕方向切换时,例如从竖屏切换到横屏时。
onRestoreInstanceState调用时机,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用。另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,也可以选择在onCreate方法中做数据还原。
1 @Override
2 protected void onRestoreInstanceState(Bundle savedInstanceState) {
4 super.onRestoreInstanceState(savedInstanceState);
5 savedInstanceState.getString("name", "");
7 }
9 @Override
10 public void onSaveInstanceState(Bundle savedInstanceState) {
11 super.onSaveInstanceState(savedInstanceState);
12 savedInstanceState.putString("name", "corn");
13 }
或在onCreate中:
1 public class AActivity extends ActionBarActivity {
2
3 private String name;
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.a);
9
10 if (savedInstanceState != null) {
11 name = savedInstanceState.getString("name");
12 }
13
14 }
15
16 }
需要注意的是,onSaveInstanceState被调用时,其调用发生在Activity生命周期中具体的位置。以A->B为例,A中onSaveInstanceState调用发生在A:onPause -> B:onCreate -> B:onResume -> A:onSaveInstanceState -> A:onStop。
onSaveInstanceState常常用于存储应用程序中当前Activity中重要的状态数据,以免Activity被系统意外杀掉的情况下当用户再次回来时不能找到之前的状态。如同一个Activity中使用多个fragment实现菜单功能时,最好需要在此函数中记录下当前菜单对应的fragment id等。