Android Activity

1.启动模式

2.生命周期

3.Activity之间跳转

启动模式:

 简单的介绍任务栈

  • APP打开时会创建一个任务栈,用于存储当前APP的Activity。
  • 任务栈包含Activity的集合,有秩序的去选择Activity与用户进行交互(任务栈最顶的Activity才能与用户直接进行交互)。
  • 任务栈会移动到后台,然后保留每一个Activity的状态,同时还会有秩序的列出它们之间的任务(它们之间的状态信息不会丢失)。
  • APP退出时,会把任务栈中的所有Activity清除,最后任务栈销毁。

 介绍任务栈的缺点:

  1. 用户每次点开一个页面,任务栈都会新添加一个Activity。如果用户点击物理返回键退出APP时,需要点击很多次,直到任务栈中的Activity全部清除完,任务栈被销毁才会退出APP(这样会造成用户体验差)。
  2. 任务栈不区分相同的数据,都保存在栈中,会造成数据冗余,内存溢出(OOM)。

  启动模式(launchMode)的作用:

  当用户点开页面时,启动模式决定是否生成新的Activity实例,是否重用已经存在的Activity实例,是否和其他的Activity实例公用一个task(task是一个具有栈结构的对象,可以管理多个Activity,启动一个APP,会创建一个与之对应的task)。

  Activity的四种启动模式介绍点击如下模式名称即可跳转到相应的模式应用场景):

  1. standard(默认模式):标准模式也是系统的默认模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。
  2. singleTop(栈顶复用模式):如果Activity已经位于任务栈的栈顶,此Activity不会被重新创建,同时它的onNewIntent方法会被调用,通过此方法的参数可以取出当前请求的数据,该Activity的onCreate和onStart不会被系统重新调用,因为它并没有重新运行。注:如果新的Activity实例已经存在但不是位于栈顶,那么新Activity会重新创建(适用于:接收通知启动的内容页面)。
  3. singleTask(栈内复用模式):这是一种单例模式,在此模式中,只要Activity在栈中存在,那么多次启动此Activity都不会重新创建实例,复用时会将它上面的Activity全部出栈,同时它的onNewIntent方法会被调用(适用于:程序入口点,如浏览器的主界面,不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上的其他页面)。
  4. singleInstance(单例模式):具备singleTask模式的所有特性,该模式的Activity只能单独的位于一个任务栈中,具有全局唯一性,整个系统中只有这一实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁。

 配置Activity的启动模式:

  在AndroidManifest.xml中的activity里面配置android:launchMode。

 启动模式应用场景点击如下的模式名称即可跳转到相应的模式介绍):

  1.standard该模式是默认模式,不配置也可以):

   content.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     android:orientation="vertical"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent">
 7     <TextView
 8         android:id="@+id/titleTxt"
 9         android:textColor="#fff"
10         android:gravity="center"
11         android:textSize="17sp"
12         android:textStyle="bold"
13         android:background="@color/colorPrimaryDark"
14         android:layout_width="match_parent"
15         android:layout_height="45dp"/>
16     <Button
17         android:id="@+id/btnJump"
18         android:layout_margin="10dp"
19         android:layout_width="match_parent"
20         android:layout_height="wrap_content"/>
21 </LinearLayout>
content.xml

    activity_main.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     android:orientation="vertical"
 8     tools:context=".MainActivity">
 9     <include layout="@layout/content"/>
10 </LinearLayout>
activity_main.xml

    MainActivity.java

 1 public class MainActivity extends AppCompatActivity implements View.OnClickListener {
 2 
 3     @Override
 4     protected void onCreate(Bundle savedInstanceState) {
 5         super.onCreate(savedInstanceState);
 6         setContentView(R.layout.activity_main);
 7         initView();
 8     }
 9 
10     private void initView(){
11         TextView titleTxt = findViewById(R.id.titleTxt);
12         titleTxt.setText(this.toString());
13         Method.setTitleTxt(titleTxt,"MainActivity");
14         Button btnJump = findViewById(R.id.btnJump);
15         btnJump.setText("跳转MainActivity");
16         btnJump.setOnClickListener(this);
17     }
18 
19     @Override
20     public void onClick(View v) {
21         Intent intent = new Intent(MainActivity.this,MainActivity.class);
22         startActivity(intent);
23     }
24 }
MainActivity.java

      Method.class

1 public class Method {
2     public static void setTitleTxt(TextView textView,String activity){
3         String value = textView.getText().toString();
4         value = value.substring(value.indexOf("@")+ 1,value.length());
5         value = "当前页面:".concat(activity).concat("  序列号:").concat(value);
6         textView.setText(value);
7     }
8 }
Method.class

   启动APP后,连续点击跳转的按钮,出现如下效果:

    序列号:44018ac

       

     序列号:ea164b3

        

      序列号:4e0d33d

      

     在MainActivity中启动MainActivity实例,序列号不同,每次点击都会重新创建MainActivity实例,stardard模式的原理如下:

    

    如上图所示, 每次跳转页面都会在任务栈中新创建一个MainActivity实例,并且放在栈的顶部,点击返回后才看到原来的实例。此模式不管有没有实例,跳转页面都会创建新的实例

  2.singleTop(此模式需要配置android:launchMode="singleTop",配置好后同样连续点击几次跳转按钮):

   序列号:44018ac -> 44018ac -> 44018ac

   

   连续点击页面中的跳转按钮,序列号都是相同的。当按返回的物理键,APP就会直接退出,说明当前的任务栈中只有一个MainActivity实例,原理如下图:

      

    如上图所示,点击跳转的按钮时,系统会在任务栈寻找是否有一个MainActivity实例,如果有不在重新创建新的实例。以上案例只实现一个页面,下面再添加一个页面实现。

   新创建一个SecondActivity,layou直接调用之前的activity_main.xml,MainActivity中修改按钮描述"跳转SecondActivity"和按钮点击事件里面的跳转新页面"Intent intent = new Intent(MainActivity.this,SecondActivity.class);"代码:

 1 public class SecondActivity extends AppCompatActivity implements View.OnClickListener {
 2 
 3     @Override
 4     protected void onCreate(Bundle savedInstanceState) {
 5         super.onCreate(savedInstanceState);
 6         setContentView(R.layout.activity_main);
 7         initView();
 8     }
 9 
10     private void initView(){
11         TextView titleTxt = findViewById(R.id.titleTxt);
12         titleTxt.setText(this.toString());
13         Method.setTitleTxt(titleTxt,"SecondActivity");
14         Button btnJump = findViewById(R.id.btnJump);
15         btnJump.setText("跳转MainActivity");
16         btnJump.setOnClickListener(this);
17     }
18 
19     @Override
20     public void onClick(View v) {
21         Intent intent = new Intent(SecondActivity.this,MainActivity.class);
22         startActivity(intent);
23     }
24 }
SecondActivity.java

  启动APP,连续点击几次跳转按钮打印出来的效果如下:

    

  相同的Activity出现不同的序列号,说明每次点击跳转按钮,它都会重新创建实例。原理图如下:

   

   当MainActivity跳转到ScondActivity,栈中有MainActivity,但栈顶不是MainActivity,所以系统会重新创建新实例。如果栈顶有相对应的实例就不会重新创建。  

  3.singleTask(此模式需要配置android:launchMode="singleTask",配置好后同样连续点击几次跳转按钮):

   MainActivity 序列号:44018ac -> SecondActivity 序列号:cd89a70 -> MainActivity 序列号:44018ac -> SecondActivity 序列号:81205ac -> MainActivity 序列号:44018ac

    跳转效果图如下:

    

    如上过程,每次MainActivity跳转到SecondActivity页面,SecondActivity的序列号是有变化的,而SecondActivity跳转到MainActivity,MainActivity的序列号是没有变化的,说明每次MainActivity跳转到SecondActivity,SecondActivity都会重新创建。原理图如下(图是根据自己的理解画的,可能不是很标准):

     

    SecondActivity跳转到MainActivity,任务栈中发现有MainActivity的实例,所以不会生成新的实例,而MainActivity之上的Activity实例都出栈,直到MainActivity实例在栈的最顶,显示到页面。

    4.singleInstance(此模式需要在SecondActivity下的activity中配置android:launchMode="singleInstance",配置好后同样连续点击几次跳转按钮):

    分别在MainActivity/SecondActivity页面加入this.getTaskId,当前的任务栈。

     

    如上图发现,两个实例分别放在不同的任务栈中,原理如下图:

     

      MainActivity跳转到SecondActivity的时候,重新启动了一个Task,用来放置SecondActivity的实例。按下返回的物理键后退时,会再次回到原来的Task,右图SecondActivity跳转到MainActivity的时候,MainActivity会重新生成新的实例,点击两次物理返回键,APP并没有退出,而是回到SecondActivity页面。这里会有疑问?为什么会回到SecondActivity。当SecondActivity跳转到MainActivity的时候APP的起点就变成了SecondActivity实例所在的Task,而不是MainActivity。

   启动模式到这里就结束了(图绘制的不好,请勿嫌弃,注:上面有GIF的效果图,如果没有看到显示,就重新刷新一下页面

 

生命周期:

  生命周期有7个方法,分别为:

   1.onCreate():Activity首次加载时,onCreate方法就会执行,如果Activity被销毁后(onDestroy后),再重新加载进Task时,onCreate方法会重新执行。

   2.onStart():Activity调用显示在屏幕时,onStart()方法可调用。onCreate事件之后执行,或当前窗体被交换到后台后,在用户重新查看窗体前已经过去了一段时间,窗体已经执行了onStop事件,但是窗体和其所在进程并没有被销毁,用户再次重新查看窗体时会执行onRestart事件,之后会跳过onCreate事件,直接执行窗体的onStart事件。

   3.onResume():Activity开始与用户交互时调用(无论是启动还是重新启动一个Activity,该方法都会被调用),onStart事件之后执行,或当前窗体被交换到后台后,在用户重新查看窗体时,窗体还没有被销毁,也没有执行过onStop事件(窗体还继续存在Task中),则会跳过窗体的onCreate和onStart事件,直接执行onResume事件。

    4.onPause():Activity被暂时或收回CPU和其他资源时调用,该方法用于保存活动状态的。窗体被交换到后台时执行。

    5.onStop():Activity被停止并转为不可见阶段及后续的生命周期事件时调用。onPause事件之后执行。如果一段事件内用户还没有重新查看该窗体,则该窗体的onStop事件将会被执行,或者用户直接按物理返回键,该窗体从当前Task中移除,也会被执行该窗体的onStop事件。

    6.onRestart():重新启动Activity时调用,该活动依然在任务栈中,而不是启动新的活动。onStop事件执行之后,如果窗体和其所在的进程没有被系统销毁,此时用户又重新查看该窗体,则会执行窗体onRestart事件,onRestart事件后会跳过窗体的onCreate事件直接执行onStart事件

     7.onDestroy():Activity被完全从系统内存中移除时调用,该方法被调用可能是因为其他地方调用onFinish()方法,或者系统决定停止该活动以释放资源。Activity被销毁的时候执行。在窗体的onStop事件之后,如果没有再次查看该窗体,Activity则会被销毁。

 生命周期流程图(绘制的不好,请勿嫌弃):

   

   生命周期的四个阶段:

   1.开始Activity:在这个阶段依次执行三个生命周期方法:onCreate、onStart和onResume。

   2.Activity失去焦点:如果在Activity获得焦点的情况下进入其他的Activity或应用程序,这时当前的Activity会失去焦点,在这一阶段,会依次执行onPause和onStop方法。

    3.Activity重新获得焦点:如果Activity重新获得焦点,会依次执行三个生命周期方法:onRestart、onStart和onResume.

    4.关闭Activity:当Activity被关闭时系统会依次执行三个生命周期方法:onPause、onStop和onDestroy。

  生命周期就到此了,最后附上摘要,点我跳转

 

Activity之间跳转:

  Activity跳转通过Intent,Intent的跳转方式有两种,分别为:

   显式Intent:通过提供目标应用的软件包名称或完全限定的组件类名来指定可处理Intent的应用。通常会在自己的应用中使用显示Intent来启动组件,这是因为已知的Activity和服务类名。

    显示的跳转方法有四种,分别为:

     1.在构造函数中指定

1 Intent intent = new Intent(this,SecondActivity.class);
2 startActivity(intent);
View Code

     2.使用setClass方法

1 Intent intent = new Intent(); 
2 intent.setClass(this,SecondActivity.class);
3 startActivity(intent);
setClass

     3.使用setClassName方法

1 Intent intent = new Intent();
2 intent.setClassName(this,"com.example.studioandroid.SecondActivity");
3 startActivity(intent);
setClassName

     4.使用setComponent方法

1 Intent intent = new Intent();
2 //setComponent方法跳转可以如下一种都行
3 intent.setComponent(new ComponentName(this,SecondActivity.class));
4 //intent.setComponent(new ComponentName(this,"com.example.studioandroid.SecondActivity"));
5 startActivity(intent);
setComponent

 

   隐式Intent:不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理。

    隐式需要在AndroidManifest.xml文件中,在需要调用的Activity中配置。Activity带有<intent-filter>元素,该元素下分别有:

     <action>:在name属性中,声明接受的Intent的操作,该值必须是操作的文本字符串值,而不是类常量。

     <category>:在name属性中,声明接受的Intent类别,该值必须有操作的文本字符串值,而不是类常量(必须将CATEGORY_DEFAULT类别包括在Intent过滤器中,否则Intent不会解析Activity)。

     <data>:使用一个或多个指定数据URL(scheme、host、port、path)各个方面和MIME类型的属性,声明接受的数据类型。

      举个栗子(action设置的字符,表达自己的意思给系统,系统解析,然后处理):

       在AndroidManifest.xml中配置跳转的Activity的元素:

1 <activity android:name=".SecondActivity">
2     <intent-filter>
3         <action android:name="老二"/>
4         <category android:name="android.intent.category.DEFAULT"/>
5     </intent-filter>
6 </activity>
View Code

         使用Intent的setActon方法,设置的action元素值要一致:

1 Intent intent = new Intent();
2 intent.setAction("老二");
3 startActivity(intent);
setAction
posted @ 2020-07-16 16:47  蒜香小龙虾  阅读(243)  评论(0编辑  收藏  举报