文章目录
作业:活动的生命周期和启动
1、通过在不同的活动之间的转换,观察onCreate, onStart, onResume, on Pause, onStop,onDestroy以及onRestart函数的调用情况。
2、通过实验说明存在系统可能自行对活动运行onDestroy。
3、利用saveinstantstate处理系统自行运行onDestroy而导致数据丢失的情况
4、通过实验说明活动的standard, singleTop, singleTask三种启动模式之间的区别点。
附加题:说明活动singleInstance启动模式的功能
评分标准:所有实验都完成起评为85分,附加题5分。其它分数增减根据报告情况
理论知识
返回栈
我们可以看到,Android的活动是层叠嵌套的,启动新活动会覆盖在原活动之上,点击back会销毁最上面的活动,下面紧跟的活动就会重新显示出来。
Android使用任务(Task)管理活动,一个任务就是存放在栈里的活动集合,这个栈也被称作返回栈(Back Stack)。
活动状态
每个活动在其生命周期最多可能会有4种状态。
活动状态 | 描述 |
---|---|
运行状态 | 活动位于栈顶 |
暂停状态 | 活动不在栈顶,但仍然可见 |
停止状态 | 活动不在栈顶,且完全不可见(即被覆盖) |
销毁状态 | 活动被返回栈移除 |
活动的生存期
Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节。
活动的回调方法 | 详细说明 |
---|---|
onCreate() | 每个活动重写此方法,它在活动第一次被创建时调用。完成初始化操作,如加载布局、绑定事件等 |
onDestroy() | 在活动销毁之前被调用,此后活动状态将变成销毁状态 |
onResume() | 活动即将与用户交互,此时活动那个位于栈顶,处于运行状态 |
onPause() | 在系统准备启动或者恢复另一个活动时调用 |
onStart() | 在活动由不可见变成可见时调用 |
onStop() | 在活动完全不可见的时候调用 |
onRestart() | 活动由停止状态变成运行状态之前调用 |
活动的启动模式
实际项目中,需要根据特定的需求为每个活动指定恰当的启动模式。
启动模式有四种,分别是standard、singleTop、singleTask 和 singleInstance。
通过Manifest.xml仓库文件的<activity>标签指定android:launchMode属性选择启动模式。
活动的默认启动模式是standard,在这个模式下,每次启动一个新的活动,它就会在返回栈中入栈并处于栈顶,系统不在乎这个活动已经在返回栈中存在,而是创建该活动的一个新的实例。
当活动位于栈顶时,我们完全没必要新建一个活动实例,所以在启动活动时检查栈顶,如果栈顶已经是该活动,则直接使用该栈顶实例。这种启动模式称为singleTop。
但其实返回栈存在活动实例时,我们完全没必要新建一个活动实例,所以在启动活动时检查返回栈,如果返回栈已经有该活动,则直接使用该返回栈实例。这种启动模式称为singleTask。
实验过程
创建活动并编写代码
创建主活动后,需要分别再创建两个子活动:normalActivity和dialogActivity。因为子活动分为完全覆盖和部分覆盖,两种情况对应的主活动状态是不同的。
本部分概述:主活动MainActivity.java,定义两个按钮进行页面跳转,重写7个回调函数并嵌套Log.d()函数,用于打印和观察主活动所处的生命周期。
布局文件activity_normal.xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="this is normal_activity"
/>
</LinearLayout>
布局文件activity_dialog.xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="this is dialog_activity"
/>
</LinearLayout>
在Manifest.xml仓库文件中注册dialog活动,设置为对话框式主题:
<activity android:name=".dialog"
android:theme="@style/Theme.AppCompat.Dialog"
></activity>
<activity android:name=".normalActivity" />
主活动MainActivity.java:
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainActivity" ; // 定义字符串变量,用于提示主活动
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,"onCreate");
Button button_normal = (Button) findViewById(R.id.button_normal);
button_normal.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, normalActivity.class);
startActivity(intent);
}
});
Button button_dialog = (Button) findViewById(R.id.button_dialog);
button_dialog.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent_dialog = new Intent(MainActivity.this, dialog.class);
startActivity(intent_dialog);
}
});
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop");
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "onRestart");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
效果图:
1.通过活动转换观察7个回调函数的使用情况
点击操作 | Logcat界面显示 | 说明 |
---|---|---|
操作一 | - | 见图二 |
点击跳转normal页面 | 出现onPause和onStop | 主页面暂停,且不可见 |
返回到主页面 | onRestart、onStart、onResume | 重新启动、可见、交互运行 |
操作二 | - | 见图三 |
点击跳转dialog页面 | 出现onPause | 主页面暂停 |
返回到主页面 | onResume | 重新启动 |
操作三 | - | 见图四 |
点击返回退出程序 | 出现onPause、onStop、onDestroy | 系统 |
2.通过实验说明存在系统可能自行对活动运行onDestroy
活动进入停止状态时,系统可能因为内存不足销毁回收该页面。
场景:用户在活动A的基础上启动了活动B,此时系统回收活动A,用户点击Back键返回活动A,此时会执行活动A的onCreate()方法。
存在问题:活动A可能存在临时数据和状态,比如用户正在活动A输入文字,突然弹出一个活动B,此时用户的输入会被清空。
解决办法:Activity提供onSaveInstanceState()回调方法,该方法在活动回收前一定会被调用,因此可以通过这个方法来保存临时数据。
由于实验环境下的系统内存相对充足,在normal页面停留十分钟,系统仍然没有销毁主页面,所以这部分没有截图。
3.利用saveinstantstate保存临时数据
在MainActivity.java中添加onSaveInstanceState()函数代码,在onCreate()函数代码中添加 if()语句:
protected void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putString("data_key", tmpdata);
}
onCreate()函数代码:
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState != null){
String tmpdata = savedInstanceState.getString("data_key");
Log.d(TAG, tmpdata);
}
4.说明活动的standard, singleTop, singleTask三种启动模式之间的区别点
standard
实验代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("FirstActivity", this.toString()); // 打印本实例信息
Button button_normal = (Button) findViewById(R.id.button_normal);
button_normal.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MainActivity.class);
startActivity(intent);
}
});
}
}
点击按钮,使页面跳转到自己,观察Logcat窗口,可以发现每点击一次,就会产生一个新的实例,而我们需要点击对应次数的back才能退出程序:
singleTop
实验代码
在仓库文件中为当前主活动添加启动模式,主活动代码与standard保持不变:
<activity android:name=".MainActivity"
android:launchMode="singleTop">
此时点击,程序不会生成主活动的新实例。但如果该活动实例不在栈顶,比如在Second活动的基础上跳转到主活动,那么还会生成主活动的新实例。
singleTask
实验代码
在仓库文件中为当前主活动添加启动模式,主活动代码与standard保持不变:
<activity android:name=".MainActivity"
android:launchMode="singleTask">
报错gradle project sync failed
原因:在仓库文件Manifest.xml空白行添加了注释: //四种启动模式
解决办法:删掉Manifest.xml文件中的注释。
反思
问题:课上跟着教授做一遍,课后跟着参考书籍又梳理一遍,时间欠费了。
解决办法:课上边听边梳理,整理好理论知识、准备好实验代码,等待任务发布。