Android四大组件之Activity

作者: MonkeyLqj | 来源:发表于2018-08-14 01:07 被阅读77次

    Android最重要的是四大组件,分别为Activity、Service、ContentProvider、Broadcast。Activity负责UI元素的加载与页面之间的跳转,代表了一个页面单元;Service负责与UI无关的工作,如在后台执行耗时操作等;ContentProvider负责存储、共享数据,使得数据可以再多个应用之间共享;Broadcast则是在各个组件、应用之间进行通信,简化了Android开发中的通信问题。
    本文学习Android的四大组件中的Activity。

    Activity

    Activity是一个应用组件,用户可与其提供的屏幕进行交互,我们在应用程序中能看到的内容,绝大多数都是Activity组件提供的。同时,Activity还可以在不同的Activity之间跳转,将不同的页面串连在一起,共同完成特定的操作流程。每个应用都是由一个或者多个Activity组成,它是Android应用程序中不可缺少的部分。

    一、创建Activity

    我们刚创建一个应用程序的时候,会给我们创建一个默认的MainActivity

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //加载布局文件
            setContentView(R.layout.activity_main);
              }
    }
    

    当我们的程序创建好,会默认有一个onCreate()方法,其中"R.layout.activity_main"是绘制UI控件的,如TextView、Button等控件。

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:tools="http://schemas.android.com/tools"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       tools:context=".MainActivity">
    
     <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content" 
           android:text="Hello World!"/>
    
    </RelativeLayout>
    

    这个activity在AndroidManifest.xml中会被设置为如下intent-filter:

       <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
        </application>
    

    其中<action>元素指定这是应用的“主”入口点。
    <category>元素指定此 Activity 应列入系统的应用启动器内(以便用户启动该 Activity)。

    二、Activity的生命周期

    程序创建好可以直接运行了,接下来我们就需要了解其生命周期,在不同的阶段会回调不同的生命周期函数,Activity的生命周期函数如下:

    1. onCreate()
      每个Activity中我们都会重写这个方法。首次创建 Activity 时调用。 我们应该在此方法中执行所有正常的静态设置 — 创建视图、将数据绑定到列表等等。
    2. onRestart()
      这个方法在Activity由停止状态变为运行状态之前调用,也就是Activity被重新启动了。
    3. onStart()
      这个方法在Activity不可见变为可见的时候调用。
    4. onResume()
      这个方法在Activity准备好和用户进行交互的时候调用,此时的Activity一定位于返回栈的栈顶、并且处于运行状态。
    5. onPause()
      这个方法在系统准备去启动或者恢复另一个Activity的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使用。
    6. onStop()
      这个方法在Activity完全不可见的时候调用。它和onPause()方法主要区别在于,如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而onStop()方法不会执行。
    7. onDestroy()
      这个方法在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。

    为了帮助读者能够更好的理解,Android 官方提供了Activity生命周期示意图,如下:


    Activity的生命周期示意图

    让我们用代码来体验下Activity的生命周期

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.e("TAG","---MainActivity--onCreate-----");
            findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //启动第二个activity
                    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                    startActivity(intent);
                }
            });
        }
        @Override
        protected void onRestart() {
            super.onRestart();
            Log.e("TAG","---MainActivity--onRestart-----");
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.e("TAG","---MainActivity--onStart-----");
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.e("TAG","---MainActivity--onResume-----");
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            Log.e("TAG","---MainActivity--onPause-----");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.e("TAG","---MainActivity--onStop-----");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.e("TAG","---MainActivity--onDestroy-----");
        }
    }
    

    运行结果如下:

    程序刚启动时执行
    TAG: --MainActivity--onCreate--
    TAG: --MainActivity--onStart--
    TAG: --MainActivity--onResume--
    当按下Home键时执行
    TAG: --MainActivity--onPause--
    TAG: --MainActivity--onStop--
    再次启动时程序时执行
    TAG: --MainActivity--onRestart--
    TAG: --MainActivity--onStart--
    TAG: --MainActivity--onResume--
    当启动第二个activity时执行
    TAG: --MainActivity--onPause--
    TAG: --SecondActivity--onCreate--
    TAG: --SecondActivity--onStart--
    TAG: --SecondActivity--onResume--
    TAG: --MainActivity--onStop--
    在SecondActivity中按下返回键执行
    TAG: --SecondActivity--onPause--
    TAG: --MainActivity--onRestart--
    TAG: --MainActivity--onStart--
    TAG: --MainActivity--onResume--
    TAG: --SecondActivity--onStop--
    TAG: --SecondActivity--onDestroy--
    当设备旋转的时候执行
    TAG: --MainActivity--onPause--
    TAG: --MainActivity--onStop--
    TAG: --MainActivity--onDestroy--
    TAG: --MainActivity--onCreate--
    TAG: --MainActivity--onStart--
    TAG: --MainActivity--onResume--

    由此可以看出Activity可以分为三种生存期:

    1. Activity 的整个生命周期发生在onCreate()与 onDestroy()方法之间,Activity 应在onCreate()中执行“全局”状态设置(例如初始化布局),并在onDestroy()中释放所有已创建的资源。
    2. Activity 的可见生命周期发生在onStart()与onStop()方法之间,在这段时间,用户可以在屏幕上看到Activity 并与其交互。
    3. Activity 的前台生命周期发生在onResume()与onPause()方法之间,在这段时间,Activity 位于屏幕上的所有其他 Activity 之前,并具有用户输入焦点(用户可以对其进行操作)。

    三、Activity的启动模式

    每个Activity都有一个相应的启动模式,启动模式一共有四种,分别是standard、singleTop、singleTask、singleInstance,可以在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。

    为了打印方便,定义一个基础Activity,在其onCreate方法和onNewIntent方法中打印出当前Activity的日志信息,主要包括所属的task,当前类的hashcode值

    public class BaseActivity extends AppCompatActivity {
    
      @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.e("TAG", "*******onCreate()*********");
            Log.e("TAG", "onCreate:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
        }
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
    
            Log.e("TAG", "====onNewIntent()===");
            Log.e("TAG", "===onNewIntent:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode()+"====");
        }
    }
    

    1. standard
    standard 是Activity的默认启动模式,每启动一个Activity就会在栈顶创建一个新的实例,当Activity已经位于栈顶时,而再次启动Activity时还需要在创建一个新的实例,不能直接复用。
    其配置如下

    <activity android:name=".MainActivity "  android:launchMode="standard"/>
    

    具体代码如下:

    public class MainActivity extends BaseActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Log.e("TAG","---MainActivity--onCreate-----");
    
                    Intent intent = new Intent(MainActivity.this, MainActivity.class);
                    startActivity(intent);
                }
            });
        }
    
        @Override
        protected void onRestart() {
            super.onRestart();
            Log.e("TAG","---MainActivity--onRestart-----");
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.e("TAG","---MainActivity--onStart-----");
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.e("TAG","---MainActivity--onResume-----");
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            Log.e("TAG","---MainActivity--onPause-----");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.e("TAG","---MainActivity--onStop-----");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.e("TAG","---MainActivity--onDestroy-----");
        }
    
    }
    

    在这里我们直接使用MainActivity再次启动一个MainActivity,多点几次按钮看看效果是什么样的

    TAG: *******onCreate()*********
    TAG: onCreate:MainActivity TaskId: 2214 hasCode:79599417
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onCreate-----
    TAG: ---MainActivity--onPause-----
    TAG: *******onCreate()*********
    TAG: onCreate:MainActivity TaskId: 2214 hasCode:123556960
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onStop-----
    TAG: ---MainActivity--onCreate-----
    TAG: ---MainActivity--onPause-----
    TAG: *******onCreate()*********
    TAG: onCreate:MainActivity TaskId: 2214 hasCode:164071754
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onStop-----
    TAG: ---MainActivity--onCreate-----
    TAG: ---MainActivity--onPause-----
    TAG: *******onCreate()*********
    TAG: onCreate:MainActivity TaskId: 2214 hasCode:170963973
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onStop-----

    可以看到MainActivity 的日志,从刚启动MainActivity,到后来我们又按了三次按钮,总共四次MainActivity 的日志,并且所属的任务栈的id都是2214 ,这也验证了谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中,我么可以发现每一个Activity的hashcode都是不一样的,说明他们是不同的实例,即每次启动一个Activity都会重写创建一个新的实例

    2. singleTop
    singleTop栈顶复用模式,如果新的activity已经位于栈顶,那么这个Activity不会被重写创建,同时它的onNewIntent方法会被调用,通过此方法的参数我们可以去除当前请求的信息。如果栈顶不存在该Activity的实例,则情况与standard模式相同。需要注意的是这个Activity它的onCreate(),onStart()方法不会被调用,因为它并没有发生改变。
    配置如下:

      <activity android:name=".MainActivity"  android:launchMode="singleTop"/>
    

    在这里我们继续使用MainActivity的方法执行下程序
    日志信息如下:

    TAG: *******onCreate()********* 刚启动程序
    TAG: onCreate:MainActivity TaskId: 2214 hasCode:79599417
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onCreate-----
    TAG: ---MainActivity--onPause-----
    ====onNewIntent()=== 第二次创建MainActivity
    TAG: ===onNewIntent:MainActivity TaskId: 2214 hasCode:79599417====
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onCreate-----
    TAG: ---MainActivity--onPause-----
    ====onNewIntent()=== 第三次创建MainActivity
    TAG: ===onNewIntent:MainActivity TaskId: 2214 hasCode:79599417====
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onCreate-----
    TAG: ---MainActivity--onPause-----
    ====onNewIntent()=== 第四次创建MainActivity
    TAG: ===onNewIntent:MainActivity TaskId: 2214 hasCode:79599417====
    TAG: ---MainActivity--onResume-----

    由此我们可以看出,除了第一次进入MainActivity这个Activity时,输出的是onCreate方法中的日志,后续的都是调用了onNewIntent方法,并没有调用onCreate方法,并且四个日志的hashcode都是一样的,说明栈中只有一个实例。这是因为第一次进入的时候,栈中没有该实例,则创建,后续的三次发现栈顶有这个实例,则直接复用,并且调用onNewIntent方法。那么假设栈中有该实例,但是该实例不在栈顶情况又如何呢?
    其配置如下:

      <activity android:name=".MainActivity" android:launchMode="singleTop">
      <activity android:name=".SecondActivity" android:launchMode="singleTop" />
      <activity android:name=".OtherActivity" android:launchMode="singleTop"/>
    

    TAG: *******onCreate()*********
    TAG: onCreate:MainActivity TaskId: 2215 hasCode:79599417
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onCreate-----
    TAG: ---MainActivity--onPause-----
    TAG: *******onCreate()*********
    TAG: onCreate:SecondActivity TaskId: 2215 hasCode:179525260
    TAG: ---SecondActivity--onCreate-----
    TAG: ---SecondActivity--onStart-----
    TAG: ---SecondActivity--onResume-----
    TAG: ---MainActivity--onStop-----
    TAG: ---SecondActivity--onPause-----
    TAG: *******onCreate()*********
    TAG: onCreate:OtherActivity TaskId: 2215 hasCode:242469764
    TAG: ---OtherActivity--onCreate-----
    TAG: ---OtherActivity--onStart-----
    TAG: ---OtherActivity--onResume-----
    TAG: ---SecondActivity--onStop-----
    TAG: ---OtherActivity--onPause-----
    TAG: *******onCreate()*********
    onCreate:MainActivity TaskId: 2215 hasCode:185437057
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---OtherActivity--onStop-----

    我们看到从MainActivity进入到SecondActivity 时,新建了一个SecondActivity 对象,并且task id与MainActivity是一样的,然后从SecondActivity 跳到OtherActivity时,新建了一个OtherActivity,此时task中存在三个Activity,从栈底到栈顶依次是MainActivity,SingleTopActivity,OtherActivity,此时如果再跳到MainActivity,即使栈中已经有MainActivity实例了,但是依然会创建一个新的MainActivity实例,这一点从上面的日志的hashCode可以看出,此时栈顶是MainActivity,如果再跳到MainActivity,就会复用栈顶的MainActivity,即会调用MainActivity的onNewIntent方法。这就是上述日志的全过程。
    singleTop模式总结
    1). 当前栈中已有该Activity的实例并且该实例位于栈顶时,不会新建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent方法。
    2). 当前栈中已有该Activity的实例但是该实例不在栈顶时(或者该栈内不存在activity的实例),其行为和standard启动模式一样,依然会创建一个新的实例。

    3. singleTask
    singleTask-栈内复用模式,在这个模式下,如果栈中存在这个Activity的实例就会复用这个Activity,不管它是否位于栈顶,复用时,会将它上面的Activity全部出栈,并且会回调该实例的onNewIntent方法。其实这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过taskAffinity属性指定。如果这个任务栈不存在,则会创建这个任务栈。
    在这里我们继续使用执行流程,只需修改下配置文件:

      <activity android:name=".MainActivity" android:launchMode="singleTask">
      <activity android:name=".SecondActivity" android:launchMode="singleTask" />
      <activity android:name=".OtherActivity" android:launchMode="singleTask"/>
    

    TAG: *******onCreate()*********
    TAG: onCreate:MainActivity TaskId: 2218 hasCode:79599417
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onCreate-----
    TAG: ---MainActivity--onPause-----
    TAG: *******onCreate()*********
    TAG: onCreate:SecondActivity TaskId: 2218 hasCode:44397022
    TAG: ---SecondActivity--onCreate-----
    TAG: ---SecondActivity--onStart-----
    TAG: ---SecondActivity--onResume-----
    TAG: ---MainActivity--onStop-----
    TAG: ---SecondActivity--onPause-----
    TAG: *******onCreate()*********
    onCreate:OtherActivity TaskId: 2218 hasCode:106765719
    TAG: ---OtherActivity--onCreate-----
    TAG: ---OtherActivity--onStart-----
    TAG: ---OtherActivity--onResume-----
    TAG: ---SecondActivity--onStop-----
    TAG: ---SecondActivity--onDestroy-----
    TAG: ---OtherActivity--onPause-----
    TAG: ====onNewIntent()===
    TAG: ===onNewIntent:MainActivity TaskId: 2218 hasCode:79599417====
    TAG: ---MainActivity--onRestart-----
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---OtherActivity--onStop-----
    TAG: ---OtherActivity--onDestroy-----

    由此我们可以看出,都在同一个栈内,当我们执行一圈后,再次回到MainActivity 中时,会调用onNewIntent()方法,不会在执行OnCreate()方法,而其中的SecondActivity和OtherActivity已经销毁了,这点是和singleTop不一样的。
    我们在开发中会碰到如下需求:
    我们从ActivityA---> B --->C --->A,回到A时,需要销毁掉BC;这时候我们就需要使用singleTask模式了,如果使用默认模式,回到A时,当我们点击返回键的时候,还是会回到C中的。

    4. singleInstance
    singleInstance-全局唯一模式,这是一种加强的singleTask模式,它除了具有singleTask模式的所有特性外,还加强了一点,那就是具有此种模式的activity只能单独的位于一个任务栈中。也就是说整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。
    我们继续使用上面的案例:
    配置如下

      <activity android:name=".MainActivity" android:launchMode="singleInstance">
      <activity android:name=".SecondActivity" android:launchMode="singleInstance" />
      <activity android:name=".OtherActivity" android:launchMode="singleInstance"/>
    

    运行结果如下

    TAG: *******onCreate()*********
    TAG: onCreate:MainActivity TaskId: 2222 hasCode:79599417==
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---MainActivity--onCreate-----
    TAG: ---MainActivity--onPause-----
    TAG: *******onCreate()*********
    TAG: onCreate:SecondActivity TaskId: 2223 hasCode:44397022
    TAG: ---SecondActivity--onCreate-----
    TAG: ---SecondActivity--onStart-----
    TAG: ---SecondActivity--onResume-----
    TAG: ---MainActivity--onStop-----
    TAG: ---SecondActivity--onPause-----
    TAG: *******onCreate()*********
    TAG: onCreate:OtherActivity TaskId: 2224 hasCode:106765719
    TAG: ---OtherActivity--onCreate-----
    TAG: ---OtherActivity--onStart-----
    TAG: ---OtherActivity--onResume-----
    TAG: ---SecondActivity--onStop-----
    TAG: ---OtherActivity--onPause-----
    TAG: ====onNewIntent()===
    TAG: ===onNewIntent:MainActivity TaskId: 2222 hasCode:79599417==

    TAG: ---MainActivity--onRestart-----
    TAG: ---MainActivity--onStart-----
    TAG: ---MainActivity--onResume-----
    TAG: ---OtherActivity--onStop---

    由此我们可以看出,前三次taskId 是不一样的,也就是说它们不在同一个栈内,而当我们再次回到MainActivity中时他会调用onNewIntent(),不会再执行onCreate()方法,因为已经存在了一个实例,不会再创建新的Task,直接复用该实例,并且回调onNewIntent方法。可以从他们的hashcode中可以看出这是同一个实例。

    四、Activity的Flags

    Activity的Flags有很多,在这里只看几个常用的标记位。其中有的标记位可以设定Activity的启动模式,
    1. FLAG_ACTIVITY_NEW_TASK
    这个标记位的作用是为Activity指定singleTask启动模式,其效果和在清单文件中指定相同。
    2. FLAG_ACTIVITY_SINGLE_TOP
    这个标记位的作用是为Activity指定singleTop启动模式,其效果和在清单文件中指定相同。
    3. FLAG_ACTIVITY_CLEAR_TOP
    具有此标记位的Activity,当它启动时,在同一个任务栈中,所有位于它上面的Activity都要出栈。
    使用方式:

     Intent intent = new Intent(MainActivity.this, SecondActivity.class);
     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     startActivity(intent);
    

    关于Activity就学习到这里,如果理解的有问题,还望指正。

    参考资料:

    1. Android开发艺术探索
    2. https://developer.android.google.cn/guide/components/activities
    3. https://blog.csdn.net/mynameishuangshuai/article/details/51491074

    相关文章

      网友评论

        本文标题:Android四大组件之Activity

        本文链接:https://www.haomeiwen.com/subject/saqdbftx.html