安卓的Activity活动栈
多个安卓Activity中的先后次序问题,需要用活动栈机制

如图:
- 每当新打开一个Activity时,会入栈,此时只有这个Activity是活动状态
- 除了栈顶的Activity其余的都处于暂停或者停止状态
- 如果内存不足,需要杀死Activity时,会释放资源使Activity处于非活动状态
安卓Activity的活动状态
分为四种:
- 活动状态:在活动栈处于栈顶的Activity,能被用户看到且可以交互,简单来说就是屏幕当前的Activity
- 暂停状态:当前Activity被部分遮挡,不再处于活动栈栈顶,并且无法交互。这里的部分遮挡是要被Activity遮挡,弹出框之类的不算被遮挡
- 停止状态:当前Activity被完全遮挡。比如按下HOME键或者跳转到别的页面
- 非活动状态:不是上面三种状态的Activity,例如被销毁的Activity
Activity活动状态切换触发回调方法
如图,转化过程如下:
- 当Activity生成时调用onCreate、onStart、onResume(相当于可以交互了),之后Activity开始运行
- 如果Acttvity处于暂停状态,会调用onPause
- Acitivty重新可以交互时调用onResume
- Activity变成停止状态,调用onPause和onStop
- Activity从停止状态变成活动状态,会调用onRestart和onStart和onResume方法
- 当前Activity从活动状态直接被销毁依次调用onPause、onStop、onDestory
- 当Activity处于暂停状态或者停止状态时,如果内存不足需要杀死Activty,进程终止,再打开需要重新生成
代码:
package net.onest.activitych0402;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private EditText etMsg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("MainActivity","onCreate");
etMsg = findViewById(R.id.et_msg);
if (null != savedInstanceState){
Log.e("onCreate",savedInstanceState.getString("msg"));
}
}
@Override
protected void onStart() {
super.onStart();
Log.e("MainActivity","onStart");
}
@Override
protected void onRestart() {
super.onRestart();
Log.e("MainActivity","onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.e("MainActivity","onResume");
//将数据进行恢复(读取文件,查询数据库等)
}
@Override
protected void onPause() {
super.onPause();
Log.e("MainActivity","onPause");
//将页面的用户数据进行保存(文件、数据库中)
}
@Override
protected void onStop() {
super.onStop();
Log.e("MainActivity","onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("MainActivity","onDestroy");
}
public void buttonClicked(View view) {
switch (view.getId()){
case R.id.btn_dialog:
Intent intent = new Intent();
intent.setClass(MainActivity.this,
DialogActivity.class);
startActivity(intent);
break;
case R.id.btn_new:
Intent intent1 = new Intent();
intent1.setClass(MainActivity.this,
NewActivity.class);
startActivity(intent1);
// finish();
break;
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.e("MainActivity","onSaveInstanceState");
super.onSaveInstanceState(outState);
//保存用户数据
outState.putString("msg",etMsg.getText().toString());
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
Log.e("MainActivity","onRestoreInstanceState");
super.onRestoreInstanceState(savedInstanceState);
//恢复用户数据
String content = savedInstanceState.getString("msg");
//显示到界面
etMsg.setText(content);
}
}
PS:
1. 如果想处于暂停状态,需要一个Activity覆盖到当前的Activity上面,并且不是完全覆盖,操作如下:
在资源目录下的values的styles.xml文件中,写一个样式,例如:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
// 这里item是定义自己独特的地方的标签,我们需简要吧windowIsFloating设置为true
<style name="DialogActivity" parent="AppTheme">
<item name="android:windowIsFloating">true</item>
</style>
</resources>
在manifests中设置activity的样式
<activity
android:name=".DialogActivity"
android:theme="@style/DialogActivity" /> <!--此处样式改成上面写好的那个-->
跳转到这样生成的Activity上,原来的就会处于暂停状态
2.
在返回时使用finish方法结束当前Activity,而不是去跳转回原来的Activity,
如果跳转回去就会产生两个不一样的Activity
// 比如我从MainActivity跳转到NewActivity
Intent intent = new Intent();
intent.setClass(MainActivity.this,NewActivity.class);
startActivity(intent);
// 如果在NewActivity中使用finish方法就会回到MainActivity中,并且只有一个
// 如果用下面的这种方法,会产生两个MainActivity,假如第一个Activity中已经写好部分信息,跳转回去产生新的MainActivity中不会有那部分信息
Intent intent = new Intent();
intent.setClass(NewActivity.this,MainActivity.class);
startActivity(intent);
3.ToolBar工具栏
我们需要在XML中先设置一个样式=>没有ActivityBar的样式
资源位置还在刚才的styles.xml文件中写
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> => 此处parent为重点
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
然后在布局中添加一个ToolBar(需要有这个的布局中写)
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:title="新的Activity"
app:navigationIcon="@drawable/back"/> => 这个地方设置返回按钮
最后在java代码中替换掉ActivityBar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolBar); // 找到组件
toolbar.setTitle("ToolBarDemo"); // 设置标题
setSupportActionBar(toolbar); // 替换
手机的横竖屏转换时的问题
当横竖屏转换时,会将原来的Activity销毁,产生一个新的Activity,导致的问题是原来写好的内容没了。
此时有两种方法可以解决:
- 借助onPause和onRestart方法将数据存到文本或者数据库中
- 借助两个回调方法临时保持状态(第一个方法也是两个回调方法,不是那两个)
第二种的实现方式为重写onSaveInstanceState和onRestoreInstanceState方法,两个方法都有参数Bundle,借助于Bundle存键值对即可,例如:
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.e("MainActivity","onSaveInstanceState");
super.onSaveInstanceState(outState);
//保存用户数据
outState.putString("msg",etMsg.getText().toString());
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
Log.e("MainActivity","onRestoreInstanceState");
super.onRestoreInstanceState(savedInstanceState);
//恢复用户数据
String content = savedInstanceState.getString("msg");
//显示到界面
etMsg.setText(content);
}