Activity是用户接口程序,它是Android应用程序的基本功能单元,它的主要功能是提供界面。Activity是Android的核心类,该类的全名是android.app.Activity。Activity相当于C/S程序中的窗体(From)或Web程序的页面。每一个Activity提供一个可视化的区域。在这个区域可以放置各种Android组件,例如按钮、图像、文本框等。
在Activity类中有一个oncreate事件方法,一般在该方法中对Acticity进行初始化。通过setContentView方法可以设置在Activity上显示视图组件。
一个带界面的Android应用程序可以由一个或者多个Activity组成。至于这些Activity如何工作,它们之间的依赖关系,则完全取决于应用程序间的业务逻辑。
在Activity建立到摧毁的过程中需要在不同的阶段调用7个生命周期方法。这七个生命周期的定义如下:
protected void onCreate(Bundle savedInstanceState) {} //在这里创建界面,做一些数据的初始化工作;
protected void onStart() {} //到这一步变成“用户可见不可交互”的状态;
protected void onResume() {} //变成和用户可交互的,(在Activity栈系统通过栈的方式管理这些Activity,即当前Activity在栈的最上端,运行完弹出栈,则回到上一个Activity);
protected void onPause() {} //到这一步是可见但不可交互的,系统会停止动画等消耗CPU的事情。从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候你的程序的优先级降低,有可能被系统收回。在这里保存的数据,应该在onResume里读出来。
protected void onStop() {} //变得不可见 ,被下一个activity覆盖了
protected void onRestart() {}
protected void onDestroy() {} //activity被消灭
上面7个生命周期分别在4个阶段按一定顺序进行调用,
关闭Activity:当Activity被关闭时系统会依次执行3个生命周期方法—onPause、onStop和onDestory方法
Activity的生命周期如下图所示
从图中可以看出Activity包含两层循环,第一层是onPause->onResume->onPause,第二层循环是onStop->onRestart->onStart->onResume->onPause->onStop。我们可以讲两层循环看成是整个Activity生命周期中的子生命周期。第一层成为焦点生命周期,第二层为可视生命周期。也就是说,第一层循环在Acitvity焦点的获取与失去的过程中循环,这一过程中Activity是可见的。第二层循环实在Activity可见与不可见的过程中循环。
因此,Activity有如下三种生命周期:
整体生命周期:onCreate->……->onDestroy.
示例代码如下:
package com.hlh.activitydemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: ");
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart: ");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume: ");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause: ");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop: ");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "onRestart: ");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
}
按如下步骤来操作应用程序:
(1)启动应用程序
(2)按手机上的主页按钮进入主界面,然后重新进入应用程序界面
(3)关闭应用程序
按照上面步骤执行后,DDMS的Logcat打印的信息如下:
从这个例子我们可以清晰看出Activity的整个生命周期的过程。
在 Android 中,不同的 Activity 实例可能运行在一个进程中,也可能运行在不同的进程中。因此我们需要一种特别的机制帮助我们在 Activity 之间传递消息。Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。
Intent负责对操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。
通过下面实例我们可以很好的了解Activity之间的通信,在主界面中点击按钮跳转到另外一个activity,同时将数据传递给OtherActivity,绑定在TextView中。
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.toOther);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, OtherActivity.class);
intent.putExtra("msg", "hello Activity");
startActivity(intent);
}
});
}
}
OtherActivity.java
public class OtherActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
TextView tv = (TextView) findViewById(R.id.tv);
Intent intent = getIntent();
//设置文本
tv.setText(intent.getStringExtra("msg"));
}
}
note:新建立了一个Actvity后,必须在AndroidManifest.xml清单文件中的标签中注册该actvity。
<activity android:name=".OtherActivity"/>
Activity有四种加载模式(launchMode)。launchMode在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已经存在的实例,是否和其他Activity共用一个task。简单介绍一个task,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。
Activity的四种加载模式如下:
1.standard
2.singleTop
3.singleTask
4.singleInstance
我们可以在AndroidManifest.xml配置的Android:launchMode属性为以上四种之一即可。
下面我们结合实例一一介绍这四种lanchMode:
1.standard
standard模式是默认的启动方式,不用为配置android:launchMode属性即可,当然也可以指定值为standard。我们创建一个Activity,命名为FirstActivity,来演示一下标准的启动模式。FirstActivity代码如下:
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
TextView textView = (TextView) findViewById(R.id.tv);
textView.setText(this.toString());
Button button = (Button) findViewById(R.id.start);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
startActivity(intent);
}
});
}
}
FirstActivity界面中的TextView用来显示当前Activity实例的序列号,Button跳转到下一个界面
连续点击几个Button按钮,将会出现下面现象:
我们发现都是FirstActivity实例但是序列号不一样,并且我们需要按两次后退键才能返回到第一个 FirstActivity。每次跳转系统都会在task中生成一个新的FirstActivity实例,并且将其放在栈顶,当我们按下back键时,才能看到原来的FirstActivity实例。
因此总结出standard启动模式,不管有没有已经存在的实例,都会生成一个新的实例。
2.singleTop
我们在上面的基础上为指定属性android:launchMode=”singleTop”,系统就会按照singleTop启动模式处理跳转行为。我们重复上面几个动作,将会出现下面的现象:
我们看到这个跟standard的结果不同,三个序列号都一样,也就是说使用的是同一个FirstActivity实例。如果按back键,程序会立即退出。跳转时系统会先在栈结构中寻找是否有一个FirstActivity实例正位于栈顶,如果有则不再生成新的,而是直接使用。也许有人会有疑问,我只看到栈内只有一个Activity,如果是多个Activity怎么办,如果不是在栈顶会如何?我们接下来再通过一个示例来证实一下大家的疑问。
再新建一个Activity命名为SecondActivity,代码如下:
public class SecondActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(this.toString());
Button button = (Button) findViewById(R.id.start);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
startActivity(intent);
}
});
}
}
然后将之前的FirstActivity跳转代码改为:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
演示结果如下:
我们看到,两个FirstActivity的序列号是不同的,证明从SecondActivity跳转到FirstActivity时生成了新的FirstActivity实例。
我们看到,当从SecondActivity跳转到FirstActivity时,系统发现存在有FirstActivity实例,但不是位于栈顶,于是重新生成一个实例。
这就是singleTop启动模式,如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。
3.singleTask
在上面的基础上我们修改FirstActivity的属性android:launchMode=”singleTask”。演示的结果如下:
我们注意到,在上面的过程中,FirstActivity的序列号是不变的,SecondActivity的序列号却不是唯一的,说明从SecondActivity跳转到FirstActivity时,没有生成新的实例,但是从FirstActivity跳转到SecondActivity时生成了新的实例。
在这个跳转过程中系统发现有存在的FirstActivity实例,于是不再生成新的实例,而是根据栈先进后出的原则将FirstActivity之上的Activity实例统统出栈(如SecondActivity),将FirstActivity变为栈顶对象,显示到幕前。如果将SecondActivity也设置为singleTask模式,那么SecondActivity实例是不是可以唯一呢?在我们这个示例中是不可能的,因为每次从SecondActivity跳转到FirstActivity时,SecondActivity实例都被迫出栈,下次等FirstActivity跳转到SecondActivity时,找不到存在的SecondActivity实例,于是必须生成新的实例。但是如果我们有ThirdActivity,让SecondActivity和ThirdActivity互相跳转,那么SecondActivity实例就可以保证唯一。
这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。
4.singleInstance
这种启动模式比较特殊,因为它会启用一个新的栈结构,将Acitvity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。
我们修改FirstActivity的launchMode=”standard”,SecondActivity的launchMode=”singleInstance”,由于涉及到了多个栈结构,我们需要在每个Activity中显示当前栈结构的id,所以我们为每个Activity添加如下代码:
TextView textView = (TextView) findViewById(R.id.tv);
textView.setText("current task id: " + this.getTaskId());
然后再演示一下这个流程:
我们发现这两个Activity实例分别被放置在不同的栈结构中.可以发现从FirstActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构。
Android针对Activity的管理使用的是栈。你有可能不清楚什么是栈,现在来解释一下,栈是指数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除,一种先进后出的数据结构。而Android中是用task来存放Activity的。在第五小节简单介绍了一下task。这里详细介绍一下
google官网对task的定义:
A task is a collection of activities that users interact with when
performing a certain job. The activities are arranged in a stack
(the back stack), in the order in which each activity is opened.
简单来说task就是一组特定的activities集合,这些activities按照每一个被打开的顺序放到一个stack(栈)中。Activity栈可以由一个或者多个Task组成。
启动一个应用时,系统会为之创建一个task来放置Activity,默认情况下,一个Activity启动另外一个Activity时,两个Activity放入同一个task中,后者被压入前者所在的task栈中。当用户按back键,后者从栈中弹出,前者又显示在屏幕上。重点强调的是,启动其他应用的Activity时,两个Activity对用户来说好像属于同一个应用,其实这两个Activity都创建了自己的task栈。系统中task和task之间是相互独立的,当我们运行应用A时,按Home键回到主屏,启动另外一个应用B,这时应用A的task被转移到后台,刚启动的应用B的task被转移到前台,其栈顶Activity会显示在屏幕上;再次按Home键回到开始启动的应用A时,A应用的task任务栈又被转移到前台,这时系统仍然保留task的所有Activity实例。