1、Android-活动(下)
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退出程序
这时候所有的栈都已经空了
示意图如下: