Activity生命周期
1:activity四种启动方式
standard,SingleTask,SingleTop,SingleInstance
standard:是系统默认的,每次启动该activity都会创建一个实例放在返回栈中,并且置于栈顶。
SingleTop:在每次启动活动的时候如果发现栈的栈顶已经有该活动了,那么就直接使用它,不会再创建新的活动实例。如果启动的时候没有在栈顶,那么还是会创建一个新的实例,比如说A->B ,返回栈存放过程是创建A,创建B,然后B->A(并非通过back回到A),创建A实例,因为此时返回栈中栈顶是B,所以会创建A实例。
SingleTask:整个返回栈中只有一个实例。每次启动的时候,就会在返回栈中检查是否有实例,如果有实例但不在栈顶,那么就会让栈顶出栈,它称为栈顶。例子:A->B,创建A实例,创建B实例,从B->A,此时返回栈中有A实例,就会让B实例出栈,此时栈中只有A的实例,所以点击Back后就会退出程序。(只要是在A上的实例全部出栈,如ABCD,需要用到B,此时栈中AB,CD出栈)
SingleInstance:对于设置该模式的活动(Activity),会创建一个实例保存在新的返回栈中,这是因为可供其他的程序调用这个活动,达到了共享这个实例,在单个程序中如:A->B(模式SingleInstance)->C,创建A实例,创建B实例(新返回栈中),创建C实例,当点击back键时,会C弹出栈,显示A,再次点击back键,A弹出栈,显示B。原因是A和C在一个返回栈中,而B在一个新的返回栈中。
2:Activity正确使用
在实际开发中,页面很多,activity很多,所以,想要通过运行程序来判断当前所看的页面是对应哪一个activity就要创建一个父类activity,这样的话,让他们都来继承这个父类,在父类中通过OnCreate方法来执行一些公用的代码和Log日志即可。主要BaseActivity不需要在清单中注册。
所有继承该父类的activity都要调用一个父类的onCreate方法。
public class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e("BaseActivity",getClass().getSimpleName()); } }
3:Activity随时随地都可以退出
一个程序中有退出登录,这个时候就要保所有的activity,然后可以销毁所有的activity并且之后跳转到登录页面,如果想要退出到桌面,也可以加入杀死进程的代码,防止该程序进程在后台一直运行。
杀死进程代码
android.os.Process.killProcess(Process.myPid());//获取id,杀死当前id,并杀死当前进程,不可杀死其他程序进程
Activity管理类
public class ActivityCollector { public static ListlistActivity = new ArrayList<>(); /** * 添加活动 * */ public static void addActivity(Activity activity){ listActivity.add(activity); } /*删除活动*/ public static void removeActivity(Activity activity){ listActivity.remove(activity); } /*销毁所有活动*/ public static void finishAllActivity(){ for (Activity activity:listActivity) { if(!activity.isFinishing()){ activity.finish(); } } } }
4:启动Activity最佳写法
问题:假设两个Activity,FirstActivity和SecondActivity,第二个活动不是你写的,但是你需要跳转到该页面,同时需要传一些参数,此时,你可以问你同事需要传什么参数,或者自己去看需要什么参数,这样太麻烦。这时就需要优化代码,你同事可以在第二个界面就留一个方法入口,把需要的参数都列出来,你只需要用类名.方法名即可
该方法写在第二个活动里,也就是需要跳转到的页面。
/*启动最佳写法*/ public static void actionStart(Context context,String param1,String param2){ Intent intent = new Intent(context,MainActivity2.class); intent.putExtra("param1",param1); intent.putExtra("param2",param2); context.startActivity(intent); }
在MAinActivity1里调用。
MainActivity2.actionStart(this,"ceshi1","ceshi2");
5:生命周期以外的方法
- onSaveInstanceState()
- onRestoreInstanceState()
onSaveInstanceState()和onRestoreInstanceState()使用详解https://www.jianshu.com/p/27181e2e32d2
注意
1、如果是用户自动按下返回键,或程序调用finish()退出程序,是不会触发onSaveInstanceState()和onRestoreInstanceState()的。2、每次用户旋转屏幕时,您的Activity将被破坏并重新创建。当屏幕改变方向时,系统会破坏并重新创建前台Activity,因为屏幕配置已更改,您的Activity可能需要加载替代资源(例如布局)。即会执行onSaveInstanceState()和onRestoreInstanceState()的。
- 1.配置改变导致Activity被杀死,横屏变竖屏:在onStop之前会调用onSaveInstanceState()保存数据在重建Activity之后,会在onStart()之后调用onRestoreInstanceState(),并把保存下来的Bundle传给onCreate()和它会默认重建Activity当前的视图,我们可以在onCreate()中,回复自己的数据。
- 2.内存不足杀掉Activity,优先级分别是:前台可见,可见非前台,后台。
在stop()之前系统会调用onSaveInstanceState()方法,以便您的Activity可以使用一组键值对来保存状态信息。此方法的默认实现保存有关Activity视图层次结构状态的信息,例如EditText小部件中的文本或ListView的滚动位置。
static final String STATE_SCORE = "playerScore"; static final String STATE_LEVEL = "playerLevel"; ... @Override public void onSaveInstanceState(Bundle savedInstanceState) { // 保存用户自定义的状态 savedInstanceState.putInt(STATE_SCORE, mCurrentScore); savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel); // 调用父类交给系统处理,这样系统能保存视图层次结构状态 super.onSaveInstanceState(savedInstanceState); }
恢复您的Activity状态
当您的Activity在之前被破坏后重新创建时,您可以从Bundle系统通过您的Activity中恢复您的保存状态。这两个方法onCreate()和onRestoreInstanceState()回调方法都会收到Bundle包含实例状态信息的相同方法。因为onCreate()调用该方法是系统正在创建一个新的Activity实例或重新创建一个以前的实例,所以您必须Bundle在尝试读取之前检查该状态是否为空。如果它为空,那么系统正在创建一个Activity的新实例,而不是恢复之前被销毁的实例。
例如,下面是如何恢复一些状态数据onCreate():
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 记得总是调用父类 // 检查是否正在重新创建一个以前销毁的实例 if (savedInstanceState != null) { // 从已保存状态恢复成员的值 mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); } else { // 可能初始化一个新实例的默认值的成员 } ... }
onCreate()您可以选择执行onRestoreInstanceState(),而不是在系统调用onStart()方法之后恢复状态。系统onRestoreInstanceState()只有在存在保存状态的情况下才会恢复,因此您不需要检查是否Bundle为空:
public void onRestoreInstanceState(Bundle savedInstanceState) { // 总是调用超类,以便它可以恢复视图层次超级 super.onRestoreInstanceState(savedInstanceState); // 从已保存的实例中恢复状态成员 mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); }
6:onNewIntent()方法
该方法和启动模式紧密相关前提:ActivityA已经启动过,处于当前应用的Activity任务栈中;
当ActivityA的LaunchMode为Standard时:
由于每次启动ActivityA都是启动新的实例,和原来启动的没关系,所以不会调用原来ActivityA的onNewIntent方法
当ActivityA的LaunchMode为SingleTop时:
如果ActivityA在栈顶,且现在要再启动ActivityA,这时会调用onNewIntent()方法 ,生命周期顺序为:
onCreate--->onStart--->onResume---onPause>onNewIntent--->onResume
当ActivityA的LaunchMode为SingleInstance,SingleTask:
如果ActivityA已经在堆栈中,那么此时会调用onNewIntent()方法,生命周期调用顺序为:
onCreate--->onStart--->onResume---按下Home键>onPause--->onstop--->onNewIntent--->onRestart--->onstart--->onResume
注意:在内存吃紧的情况下,系统可能会kill掉后台运行的 Activity ,如果不巧要启动的那个activity实例被系统kill了,那么系统就会调用 onCreate 方法,而不调用 onNewIntent 方法。这里有个解决方法就是在 onCreate 和 onNewIntent 方法中调用同一个处理数据的方法,
总结:在activityA中设置了对应的启动模式后,其他(自己也行)activityB往A中使用intent跳转,携带值时就会调用onNewIntent()方法,然后是onRestart->onStart()->onResume();
7:Activity的启动过程
启动过程不是启动模式,所谓启动过程,就是从你看到应用图标点击后到正式开启所经过的过程
- 第一种是从桌面launcher上点击相应的应用图标
- 第二种是在activity中通过调用startActivity来启动一个新的activity
由于launcher也是一个程序,所以当我们点击应用图标的时候系统会调用startActivitySately()。(具体在第二篇作答)
8:Activity和fragment绑定后流程
fragment存在被activity动态加载和静态加载,静态加载实在xml文件中加载,