《Android开发艺术探索》之Activity的生命周期及启动模式

来源:互联网 发布:藏宝阁买号软件 编辑:程序博客网 时间:2024/05/18 01:06

 1.1 Activity的生命周期和全面分析

   典型生命周期:是指有用户参与的情况下,Activity所经历的生命周期的改变

  异常情况下的生命周期:是指界面被系统回收或者由于当前设备的configure发生改变从而导致Activity被销毁  重建。 


 1.2 典型情况下的生命周期分析

 onCreat:表示Activity正在被创建,这个方法主要做一些初始化的工作,比如调用setContentView去加载界面布局资源.初始化Activity所需数据等。

 onRestart:表示Activity正在重新启动。一般情况下,当当前Activity从不可见重新变为可见状态时    onRstart就会被调用。

 onStart:表示Activity启动,此时Activity可见,但在后台,无法和用户交互。

 onResume:表示Activity可见并在前台开始活动。

 onPause: 表示Activity停止,正常情况下onStop方法就会被调用。

 onStop:  表示Activity即将停止,可以做一些微重量级的回收工作,同样不能太耗时。

 onDestory:表示Activity即将被销毁,这个方法可以做一些回收工作和最终的资源释放。


 1.3 Activity周期分为以下几种情况

  (1) Activity第一次启动:onCreate->onStart->onResume

  (2) 当用户打开新Activity或切换到桌面的时候,回调如下:onPause->onStop

        特殊情况当Activity采用透明主题,那么当前Activity不会调用onStop

  (3)当用户再次回到原Activity时。回调如下: onRestart->onStart->onResume

  (4)当用户按下back键回退时,回调如下:onPause->onStop->onDestory

  (5)当Activity被系统回收后再次打开,生命周期回调过程和(1)相同


1.4 异常情况下的生命周期分析

 情况1:资源相关的系统配置发生改变导致Activity被杀死并被重新创建 

 其生命周期为:Activity-意外情况->onSaveInstanceState->onDestory 

                                           |重新创建

                           Activity  -> onCreate -> onRestoreInstanceState   

          当系统资源配置发生改变的时候,Activity会被销毁,其中的onPause() onStop() onDestory()都会被  调用,并且由于Activity是被异常中止,系统会在调用onStop()方法前调onSaveInstanceState()方法,至于是  在onPause()之前还时之后并没有明确的界限。当Activity被重新创建时,系统会自onRstoryInstanceState()    方法,同时将之前调用onSaveInstanceState()方法所保存的Bundle对象作为参数传onRstoryInstanceState()  方法和onCreat()方法。如果Activity被重建了,那么我们就可以取出之前保存的数据并恢复,从时序上来说,  onRestoryInstanceState()方法应该是在onState()之后。

   

情况2:资源内存不足导致低优先级的Activity被杀死 

   这种情况不好模拟,但我们可以先了解一下优先级的情况。Activity的优先级按照从高到低可以分为以下三种:

(1)前台Activity-正在和用户交互的Activity,优先级最高。

(2)可见但非前台Activity-比如Activity中弹出了一个对话框,导致Activity可见但是位于后台无法和         用户直接           交互。

(3)后台Activity-已经暂停的Activity, 比如执行了onStop, 优先级最低。

  当系统内存不足时,系统会按照上述优先级去杀死目标Activity所在的进程,并在后续              onSaveInstanceState()方法和RestoreInstanceState()方法来存储和恢复数据。如果一个进程没有四大组件在执行,那么这个进程很快就会被后台杀死,因此一些后台工作不适合脱离四大组件而独自运行在后台中,这样的进程很容易被杀死。比较好的方法就是将后台的工作放入Service中从而保证进程有一定的优先级,这样不容易被系统轻易杀死。


1.5 Activity的启动模式

 开始分析启迪模式之前先创建一个ActivityTest项目,修改其中MainActivity.java中的onCreate()方法 

 standard(标准模式)

    @Override

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("MainActivity",this.toString());
Button button=(Button)findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,MainActivity.class);
startActivities(intent);
}
});
   这段代码的意思是在MainActivity的基础上启动MainActivity,从逻辑上没什么意义,主要就是验证一下   standard模式,之后可以在log中看到,每点击一次按钮,MainActivity实例就会被创建一次,因此你需要   按下多次Back键才能退出程序。

 singleTop(栈顶复用模式)

   可能有些情况下,你会觉得standard模式不太合理。别着急,这只是系统默认的一种启动模式而已,你完全可以根据自己的需求进行修改,比如用singleTop模式,当活动指定该模式的时候,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的实例的。

   

<activity android:name=".MainActivity"
android:launchMode="singleTop"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

然后重新运行程序,查看logcat会看到已经创建了一个MainActivity的实例,不管你点击了多少次按钮都不会有新的打印信息出现,此时的MainActivity的实例位于栈顶,仅按一次Back键就可以退出程序。不过当MainActivity并不处于栈顶的位置时,这时再启动MainActivity,还是会创建新的实例的。

  

 singleTask(栈内复用模式)

   使用SingleTop模式可以很好的解决重复创建栈顶活动的问题,当活动指定的启动模式为singleTask时,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现会创建一个新的活动实例。

<activity android:name=".MainActivity"
android:launchMode="singleTask"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
然后在MainActivity中添加onRestart()方法,并打印日志:
@Override
protected void onRestart() {
super.onRestart();
Log.d("FirstActivity","onRestart");
}
最后在SecondActivity中添加onDestory()方法,并打印日志:
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("FirstActivity","onDestroy");
}
现在运行程序,在MainActivity点击按钮进入到SecondActivity,然后在SecondActivity点击按钮再回到MainActive。然后查看logcat会发现MainActivity的onRestart()方法和SecondActivity的onDestroy()方法得到执行。现在返回栈中应该只剩下一个MainActivity的实例了,按一下Back键就可以退出程序。
SingleInstance
  singleInstance模式应该算是4种启动模式中最特殊也最复杂的一个了,你也需要多花点功夫来理解这个模式。不同于以上三种模式,指定singleInstance模式的活动会启用一个新的返回栈来管理这个活动(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。那么这么做有什么意义呢?假设我们的程序中有一个活动是允许其他程序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,应该如何实现呢?
使用前面3中启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个活动在不同的返回栈中入栈必然是创建新的实例。而使用singleInstance模式就可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题。
  为了帮助你更好的理解这种启动模式,我们还是来实践一下。修改 AndroidManifest中的SecondActivity的启动模式:
<activity android:name=".SecondActivity"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="com.example.administrator.firstactivity.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.administrator.firstactivity.MY_CATEGORY"/>
</intent-filter>
</activity>
我们先把SecondActivity的启动模式指定为singleInstance,然后修改MainActivity中的onCreat()方法的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("MainActivity","Task id is"+getTaskId());
Button button=(Button)findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivities(intent);
}
});
}
在onCreat()方法中打印了当前返回栈的id。然后修改SecondActivity中的onCreat()方法的代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("SecondActivity","Task id is"+getTaskId());
Button button2=(Button)findViewById(R.id.button_2);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(SecondActivity.this,ThirdActivity.class);
startActivities(intent);
}
});
}
同样在onCreate()方法中打印了当前返回栈的id,然后又修改了按钮点击事件的代码,用于启动ThirdActivity。 最后修改ThirdActivity中的onCreat()方法的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.third_layout);
Log.d("ThirdActivity","Task id is"+getTaskId());
}
任然是在onCreate()方法中打印当前返回栈的id。现在重新运行程序,在MainActivity界面进入到SecondActivity,然后在SecondActivity界面点击进入到ThirdActivity。通过查看logcat中的打印信息,可以看到SecondActivity 的 Task id不同于MainActivity和ThirdActivity,这说明SecondActivity确实放在一个单独的返回栈中,而且这个栈只有SecondActivity这一个活动。

          然后我们按下Back键进行返回,你会发现ThirdActivity竟然直接返回到了FirstActivity,再按下Back键又会返回到SecondActivity,再按下Back键就会退出程序,这是为什么呢?

原理很简单,由于MainActivity和ThirdActivity是存放在同一个返回栈中的,当在ThirdActivity的界面按下Back键,ThirdActivity会从返回栈中出栈,那么MainActivity就成为了栈顶活动显示在界面上,因此也就出现了从ThirdActivity直接返回到MainActivity的情况。然后在MainActivity界面再次按下Back键,这时的返回栈已经空了,于是就显示了另一个返回栈的栈顶活动,即SecondActivity。最后按下Back键,这时所有的返回栈都已经空了, 也就自然退出了程序。


1.6  Activity的Flags

      Activity的Flags有很多,这里分析一些比较常用的标记位。标记位的作用有很多,有的标记位可以设置Activity的启动模式,比如FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_SINGLE_TOP等,还有的标记位可以影响Activity的运行状态,比如FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS等。


1.7 intent-Filter的匹配规则

    我们知道,启动Activity分为两种,显示调用和隐式调用。二者的区别在于,显示调用需要明确的指定启动对象的组件信息,包括包名和类名,而隐式调用则不需要明确指定组件信息。

     隐式调用需要Intent能够匹配目标组件中的Inter-Filter中所设置的过滤信息,如果不匹配将无法启动目标Activity。

      为了匹配过滤列表,需要同时过滤列表中的action,category,data信息,否则匹配失败。一个过滤列表中的action,category,data可以有多个,所有的action,category,data分别构成不同类别,同一类别的信息共同约束当前类别的匹配过程。只有一个Intent同时匹配actionleibie,category类别,data类别才算完全匹配,只有完全匹配才能启动目标Activity。另外一点,一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。


1.8 总结

   以上知识主要是介绍了Activity的生命周期和启动模式,以及IntentFilter的匹配规则,刚开始写没有什么经验,写的不好请各位多多包涵!

阅读全文
3 0
原创粉丝点击