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的生命周期函数如下:
-
onCreate()
每个Activity中我们都会重写这个方法。首次创建 Activity 时调用。 我们应该在此方法中执行所有正常的静态设置 — 创建视图、将数据绑定到列表等等。 -
onRestart()
这个方法在Activity由停止状态变为运行状态之前调用,也就是Activity被重新启动了。 -
onStart()
这个方法在Activity不可见变为可见的时候调用。 -
onResume()
这个方法在Activity准备好和用户进行交互的时候调用,此时的Activity一定位于返回栈的栈顶、并且处于运行状态。 -
onPause()
这个方法在系统准备去启动或者恢复另一个Activity的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使用。 -
onStop()
这个方法在Activity完全不可见的时候调用。它和onPause()方法主要区别在于,如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而onStop()方法不会执行。 -
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可以分为三种生存期:
- Activity 的整个生命周期发生在onCreate()与 onDestroy()方法之间,Activity 应在onCreate()中执行“全局”状态设置(例如初始化布局),并在onDestroy()中释放所有已创建的资源。
- Activity 的可见生命周期发生在onStart()与onStop()方法之间,在这段时间,用户可以在屏幕上看到Activity 并与其交互。
- 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就学习到这里,如果理解的有问题,还望指正。
参考资料:
网友评论