1.4、活动的生命周期

对于活动来说生命周期的理解时非常重要的

当对其生命周期有了足够的了解,可以很好的写出程序

1.4.1、返回栈

Android中的活动是可以层叠的

没启动一个新的活动,就会立即覆盖再原来的活动之上

点击Back就会销毁最上面的活动,上一个活动就会重新显示

Android时使用任务(Task)来管理活动的

一个任务就是一组存放在栈里的活动集合,这个栈也成为返回栈

栈是一种先进后出的数据结构

再莫瑞诺情况下,当启动一个新的活动,他会在返回栈中入栈,并且处于栈顶的位置

按下Back键的似乎或者调用finish()方法销毁一个活动,处于栈顶的活动会出栈

这时候前一个入栈的活动就会重新处于栈顶的位置。

返回栈工作示意图:

1.4.2、活动状态

每个活动在生命周期最多可能出现的4种状态

1、运行状态

当一个活动处于栈顶的时候,这个活动就处于运行状态

系统最不愿意回收的就是处于运行状态的活动,会给用户带来很差的体验

2、暂停状态

当活动不在处于栈顶的位置,但仍然可见,这个活动此时就处于暂停状态。

3、停止状态

当一个活动不在处于栈顶的位置,且完全不可见的时候,就进入了停止状态。

4、销毁状态

当一个活动从返回栈中移除后就变成了销毁状态。

系统会进行回收,保证手机内存的充足

1.4.3、活动的生命周期

Activity类中定义了七个方法

可以完全覆盖生命周期中的每一个环节:

1、onCreate()

他会在活动第一次创建的时候调用,可以实现活动的初始化:加载布局、绑定事件....

2、onStart()

这个方法是在活动由不可见变为可见的时候调用

3、onPause()

这个方法是在系统准备去启动或者恢复另一个活动的时候调用

通常用于释放资源、保存相关的数据

但是这个方法执行的速度要快,不然会影响到栈顶的活动使用

4、onStop()

在活动完全不可见的时候去调用

与onPause()方法的主要区别在于:如果启动的新活动是一个对话框式的活动,那么onPause()会执行,后者不会

5、onResume()

这个方法在获得准备好和用户进行交互的时候调用

6、onDestroy()

这个方法在活动销毁之前进行调用,之后活动的状态将变为销毁状态

7、onRestart()

这个方法在活动由停止状态变为运行状态之前调用

以上除了onRestart()方法,其他都是两两相对的

从而可以将活动分为3中生命周期

活动生命周期的示意图:

1.4.4、实践活动的生命周期

根据之前的三个项目来进行测试:

first_layout.xml

    <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/button_first"
android:text="to first"/> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/button_second"
android:text="to second"/>

定义了两个按钮,分别在监听中跳转到其他两个页面

FirstActivity.java

实现7个方法,并且进行打印每一个方法被调用的时机来确定该方法的执行实时间

public class FirstActivity extends AppCompatActivity {

    @Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
Log.d("onCreate====","onCreate");
Button first = (Button) findViewById(R.id.button_first);
first.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
}
});
Button second = (Button) findViewById(R.id.button_second);
second.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,ThirdActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onStart() {
super.onStart();
Log.d("onStart====","onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.d("onResume====","onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.d("onPause====","onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.d("onStop====","onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("onDestroy====","onDestroy");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d("onRestart====","onRestart");
}
}

second_activity.xml

这里仅仅只是一个页面数据显示,无其他的功能实现!!!

    <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="this second"/>

third_activity.xml

这里仅仅只是一个页面数据显示,无其他的功能实现!!!

    <TextView
android:text="this is first"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

启动:

可以直接观察看控制台的打印:

此时没有出发按钮的点击事件:

第一次创建FirstActivity活动时会一次执行onCreate()、onStart()、onResunme()三个方法

点击第一个按钮:

此时控制台:

由于secondActivity完全把firstActivity遮挡住

因此会执行onPause()方法和onStop()方法

点击Back键返回:

由于之前的firstActivity已经进入了停止状态

所以onRestart()方法会得到执行

之后一次执行onStart()和onResume()方法

此时的onCreate()方法不会执行

因为该活动没有重新创建

如果活动没有完全泽当当前的活动

只会执行onPause()方法

onStop()方法不会执行

此时的前一个活动只是进入了暂停状态

按Back返回

也只有onResume()方法被执行

若退出程序:

此时会一次执行以上的三个方法,最终销毁FirstActivity

1.4.5、活动被收回了怎么办?

当一个活动进入了停止状态是有可能被系统收回的

一个活动启动了零一活动,前一个活动被系统回收

再次返回到前一个活动会正常显示的

不同的是这里不会执行onRestart()方法

会执行onCreate(0方法进行重新创建活动

问题:

前一个活动中额能存在临时数据和状态

一旦返回到前一个活动会将之前的数据和状态都丢失掉

这会影响到用户的体验

Activity中提供了onSaveInstanceState()回调方法

这个方法可以保证活动在回调之前一定被调用

故可以使用这个方法进行解决回收之前数据得不到保存的问题

onSaveInstanceState()方法会携带一个参数Bundle类型的参数

Bundle提供了一系列的方法用户保存数据

如使用putString()方法来保存数据

putInt()方法来保存整形数据等

两个参数:

1、键,用于后面的Bundle取值

2、值,即是要保存的数据

在FirstActivity中:

    @Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String date = "保存的数据";
outState.putString("date",date);
}

这里的数据只是测试保存零时数据

实际开发中可能保存的是文本框中的值等

数据恢复:

 @Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout); if (savedInstanceState != null){
String date = savedInstanceState.getString("date");
Log.d("date====",date);
}
  ......
}

这里的onCreate()方法中有一个Bundle类型的参数

一般情况下是null

如果在回收之前执行了上述的报保存数据的方法,这个参数就会保存之前所有保存过的临时数据

同理使用Bundle也可以进行数据的传送!!!

1.5、活动的启动模式

在实际的开发中需要指定每个活动的启动方式

启动模式一共有4中:

1、standard

2、singleTop

3、singleTask

4、singleInstance

可以在<activity>标签中指定android:launchMode来选择启动模式

1、standard

活动的默认启动 方式,在不进行显示的指定的情况下都会默认使用这个启动模式

每启动一个活动就会在返回栈中入栈且处于栈顶的位置

对于这种模式的活动,系统不会在乎这个活动是都已经在栈中存在,每次启动都会创建该活动的新实例

测试:

    @Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout); Log.d("FirstActivity====",this.toString()); Button first = (Button) findViewById(R.id.button_first);
first.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
}
});
}

这里使用上述的Log进行打印:

启动的时候进行的打印:

有三两个实例此时需要2次Back键才能退出程序

模式的原理示意图:

2、singleTop

在启动活动的时候如果发现返回栈顶已经是该活动,则认为可以直接使用它

不会再创建新的实例

在注册文件中

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

其余不变进行测试启动:

之后不管点击按钮多少次都不会再有新的打印信息

该活动已经处于栈顶

每当想要在启动一个FristActivity都会直接使用栈顶的活动,该混动也就是只有一个实例

仅按一次Back键即可退出程序

若FirstActivity未处于栈顶的位置时,在启动FirstActivity会创建新的实例

测试:

对于SecondActivity中:

  @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity); Button button = (Button) findViewById(R.id.button_return1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this,FirstActivity.class);
startActivity(intent);
}
});
}

其余不变启动测试:

点击按钮之后再点击回退:

可以看到两个不同的FirstActivity实例

由于再SecondActivity中再次启动FirstActivity栈顶已经变成了SecondActivity

因此会创建一个新的实例

按back键就会返回到SecondActivity

再按一下back会返回到FisrstActivity

最后早按一下退出程序

原理示意图:

3、singleTask

每次启动活动时系统首先会在返回栈中检查是否存在过该活动的实例

如果发现则直接使用该实例并且把这个活动之上的所有活动统统出栈

如果没有则会创建一个新的活动实例

与SingleTop不同,后者是可以很好的解决重复出栈的问题,但是

该活动若没有处于栈顶的位置会创建多个活动的实例

FirstActivity

public class FirstActivity extends AppCompatActivity {

    @Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("FirstActivity====",this.toString());
setContentView(R.layout.first_layout); Button first = (Button) findViewById(R.id.button_first);
first.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
}
});
} @Override
protected void onRestart() {
super.onRestart();
Log.d("FirstActivity====",this.toString());
}
}

注册文件中:

<activity
android:name=".FirstActivity" android:launchMode="singleTask"
android:label="first">
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
SecondActivity.java
public class SecondActivity extends AppCompatActivity {

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity); Button button = (Button) findViewById(R.id.button_return1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this,FirstActivity.class);
startActivity(intent);
}
});
} @Override
protected void onDestroy() {
super.onDestroy();
Log.d("destory:", "活动2已经关闭");
}
}

启动时:

点击事件出发返回后:

此时可以看见该栈之上的所有栈都被关闭

此时点击一次Back就可以退出程序

原理示意图:

4、singleInstance

指定该模式的活动会启用一个新的返回栈来管理这个活动

假设我们的程序中有一个活动是可以允许其他程序调用

想实现其他程序和我们的程序可以共享这个活动的实例

使用singleInstance模式可以解决这个问题

在这个模式下会有一个单独的返回栈来管理这个活动

不管是那个应用程序来访问这个活动都公用一个返回栈,这样解决了共享活动实例的问题

配置文件中对SecondActivity进行设置

        <activity
android:name=".SecondActivity"
android:launchMode="singleInstance"></activity>

对代码进行修改:

FirstActivity.java

  @Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("FirstActivity====", String.valueOf(getTaskId()));
setContentView(R.layout.first_layout);
Button first = (Button) findViewById(R.id.button_first);
first.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
}
});
}

SecondActivity.java

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity);
Log.d(
"SecondActivity====", String.valueOf(getTaskId()));
Button button = (Button) findViewById(R.id.button_return1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this,ThirdActivity.class);
startActivity(intent);
}
});
}

ThirdActivity.java

   @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.third_activity);
Log.d("ThirdActivity====", String.valueOf(getTaskId()));
}

首先启动:

点击去SecondActivity

再点击去ThirdActivity

再back直接返回到FirstActivity

再Back直接返回到SecondActivity

再Back退出程序

这时候所有的栈都已经空了

示意图如下:

1、Android-活动(下)的更多相关文章

  1. Xamarin. Android实现下拉刷新功能

    PS:发现文章被其他网站或者博客抓取后发表为原创了,给图片加了个水印 下拉刷新功能在安卓和iOS中非常常见,一般实现这样的功能都是直接使用第三方的库,网上能找到很多这样的开源库.然而在Xamarin. ...

  2. Android studio下gradle Robolectric单元测试配置

    android studio下gradle Robolectric单元测试配置 1.Robolectric Robolectric是一个基于junit之上的单元测试框架.它并不依赖于Android提供 ...

  3. Android活动启动模式

    在android中,android活动是以栈的方式进行存储,在栈中的活动不断被重新激活至前台和不断被终止也不断被排序.因此对于栈中的活动管理也是一个比较麻烦的事情. android给我们提供了两类活动 ...

  4. Android shell 下 busybox,clear,tcpdump、、众多命令的移植

    http://my.oschina.net/mopidick/blog/167372 作为一名Android开发者,经常需要进入Android 的shell终端运行一些命令.但是我们发现Android ...

  5. S5PV210之Sate210-F DIY硬件,移植uboot,kernel,android 活动现在已经进入实施阶段吗,欢迎广大网友参与 !

    大家一起来diy 超低价四核的exynos4412或者Cortex A8S5pv210开源开发板 商业版Sate210已经完成了好久了.Sate4412 也已经出来.但是这两个接口非常全,主要是针对企 ...

  6. cocos2d-x 在android环境下开发遇到的一些bug

    今天在弄一个关于android环境下解析xml的东东,遇到了2个比较麻烦问题 1.android的apk下文件是压缩文件,io.open模式无法读取到数据的, 解决思路就是: CCFileUtils: ...

  7. Android studio 下JNI编程实例并生成so库

    Android studio 下JNI编程实例并生成so库 因为公司需要为Android相机做美颜等图像后期处理,需要使用JNI编程,最近学了下JNI,并且在Android Studio下实现了一个小 ...

  8. Android tabhost下的activity怎样获取传来的值

    android tabhost下的activity怎样获取传来的值,具体解决方案如下: 解决方案: 其他activity设置intent:Intent intent=new Intent(); int ...

  9. 【转】忙里偷闲写的小例子---读取android根目录下的文件或文件夹

    原文网址:http://www.cnblogs.com/wenjiang/p/3140055.html 最近几天真的是各种意义上的忙,忙着考试,还要忙着课程设计,手上又有外包的项目,另一边学校的项目还 ...

  10. 【转】读取android根目录下的文件或文件夹

    原文网址:http://my.oschina.net/Ccx371161810/blog/287823 读取android根目录下的文件或文件夹 SDK的操作 读取android根目录下的文件或文件夹 ...

随机推荐

  1. 前端(十二):react-redux实现逻辑

    一.context实现数据传递 在react中,props和state都可以设置数据.不同的是,props借助组件属性传递数据但不可以渲染组件,它相对来说是“静态的”:state可以监听事件来修改数据 ...

  2. hdu 3999 二叉查找树

    The order of a Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  3. jdk锁相关

    锁类型 可重入锁:在执行对象中所有同步方法不用再次获得锁 可中断锁:在等待获取锁过程中可中断 公平锁: 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利 读写锁:对资源读取和写入的 ...

  4. Java 基础:数组

    一.数组声明: int[] x; int x[]; 在Java中一般使用前者,机把int[]看做一个类型,C++中只能后者 二.数组初始化: 直接提供值: int[] x = {1, 3, 4}; i ...

  5. Thymeleaf学习记录(7)--页面引入/片段引入

    1.为页面添加footer: Templates文件夹下新建HTML文件: <!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xh ...

  6. PyCharm导入包的问题

    在此之前,我们说一下虚拟环境这个概念: 在django项目中,直接就安装各种package,可能会造成系统混乱,因为package之间会有依赖的.比方说,你现在直接装django,他会依赖其他的包(开 ...

  7. drupal7 获取网站名称

    $site_name=variable_get('site_name', 'Drupal');

  8. php自动获取上一个月的起始时间

    1.借鉴评论的方法[20170309 edit] function get_month_start_end($timestamp) { !empty($timestamp) OR $timestamp ...

  9. js只对等号左边的进行变量提升

    ### 只对等号左边的进行变量提升 > =:赋值,左边是变量,右边都应该是值 ```javascript //之前 i%2 === 0?item.className = 'c1':item.cl ...

  10. hmac 算法模块

    Hmac算法:Keyed-Hashing for Message Authentication.它通过一个标准算法,在计算哈希的过程中,把key混入计算过程中 Python自带的hmac模块实现了标准 ...