为了账号安全,请及时绑定邮箱和手机立即绑定

Android四大组件之Activity

标签:
Android

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生命周期示意图,如下:


webp

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);



作者:MonkeyLi
链接:https://www.jianshu.com/p/ca9f1650a6fb


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消