一、Activity的基本介绍
Android应用中通常由一个或者多个基本组件组成,我们平时看到的Andrid应用中最常用的组件就是Activity。Activity、BroadcastReceiver、ContentProvider和Service合称Android的四大组件。
在我们创建完一个Android工程后会有以下视图:
这个MainActivity就是我们AndroidStudio默认提供的activity。
你要知道,项目中的任何活动都要重写Activity的onCreate()方法,但目前的MainActivity内部去除掉不相干的代码后,内容如下:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
可以看到,默认实现的onCreate()方法非常简单,就是调用了父类的onCreate()方法。
Activity主要负责于和用户交互,而谈及与用户交互则不得不说Android中的View组件了。View组件是所有UI控件、容器控件的基类,可以说View组件就是Android应用中用户实实在在看到的部分。但View组件需要放到容器组件中,或者使用Activity将它显示出来。如果我们需要通过某个Activity把指定的View显示出来,调用Activity的setContentView()方法即可。
setContentView()方法可接受一个View对象作为参数,例如:
//创建一个线性布局管理器
LinearLayout layout = new LinearLayout(this);
//设置该Activity显示Layout
setContentView(layout);
这两行代码创建了一个LinearLayout对象(它是 ViewGroup的子类,ViewGroup又是View的子类),接着调用Activity的setContentView(layout)把这个布局管理器显示出来。
我们经常使用setContentView()方法接受一个布局管理器资源的ID作为参数,例如:
//设置该Activity显示main.xml文件定义的View
setContentView(R.layout.activity_main);
在初始代码中我们可以看到这一行代码:
setContentView(R.layout.activity_main);
这一行代码主要是说明当前activity引用的是activity_main布局文件,在Android项目中添加的任何资源都会在R文件中生成一个相应的资源id,因此我们的activity_main.xml布局文件的id现在应该是已经添加到R文件中了。在代码中引用布局文件的方法你也看到了,只需要调用R.layout.activity_main就可以得到activity_main.xml布局的id,然后将这个值传入setContentView()方法即可。注意这里我们使用的R是我们工程包下面的R文件,AndroidSDK还会自动提供一个android包下的R文件,注意两者是有区别的,别引用错了。
一、Activity的生命周期
谷歌官方提供的Activity生命周期图:
相信不少人已经看过这个流程图,在此就不多做赘述,我简单的说说这几个过程:
1.启动Activity:系统会先调用onCreate方法,然后调用onStart方法,最后调用onResume,Activity进入运行状态。
2.当前Activity被其他Activity覆盖其上或被锁屏:系统会调用onPause方法,暂停当前Activity的执行。
3.当前Activity由被覆盖状态回到前台或解锁屏:系统会调用onResume方法,再次进入运行状态。
4.当前Activity转到新的Activity界面或按Home键回到主屏,自身退居后台:系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。
5.用户后退回到此Activity:系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。
6.当前Activity处于被覆盖状态或者后台不可见状态,即第2步和第4步,系统内存不足,杀死当前Activity,而后用户退回当前Activity:再次调用onCreate方法、onStart方法、onResume方法,进入运行状态。
7.用户退出当前Activity:系统先调用onPause方法,然后调用onStop方法,最后调用onDestory方法,结束当前Activity。
仅仅知道还是不够的,我们要用实例来融会贯通:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate called.");
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(),SecondActivity.class);
startActivity(intent);
}
});
}
//Activity创建或者从后台重新回到前台时被调用
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart called.");
}
//Activity从后台重新回到前台时被调用
@Override
protected void onRestart() {
super.onRestart();
Log.i(TAG, "onRestart called.");
}
//Activity创建或者从被覆盖、后台重新回到前台时被调用
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume called.");
}
//Activity被覆盖到下面或者锁屏时被调用
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause called.");
//有可能在执行完onPause或onStop后,系统资源紧张将Activity杀死,所以有必要在此保存持久数据
}
//退出当前Activity或者跳转到新Activity时被调用
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop called.");
}
//退出当前Activity时被调用,调用之后Activity就结束了
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestory called.");
}
执行上述代码,点击按钮后可以看见如下TAG:
这就是一次完整的常规activity生命周期。
从某种角度看,Activity为Android应用提供了可视化用户界面,如果该Android应用需要多个用户界面,那么这个Android应用将会包含多个Activity,多个Activity组成Activity栈,当前活动的Activity位于栈顶。
提到Activity栈则不得不谈谈Activity的启动模式。
一、Activity的启动模式
Android中的activity一共有四种启动模式,分别是:standard、singleTop、singleTask和singleInstance。可以在AndroidManifest.xml中设置启动模式。
1、standard
android:launchMode="standard"
<!-- 设置为默认启动模式-->
standard是活动默认的启动模式,每开始一个activity,就会在栈中加一个activity,相同的也会加,所以加多少个,就要按多少次返回键才能回到最初的界面。
2、singleTop
android:launchMode="singleTop"
栈顶复用模式,在这种模式下,如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息。需要注意的是,此Activity的onCreate、onStart方法不会被系统调用,因为它并没有发生改变。若新Activity的实例已存在但不是位于栈顶,那么新Activity仍然会重新创建。例如:加上目前栈内的情况为ABCD,其中ABCD为四个Activity,A位于栈底,D位于栈顶,这个时候假设要再次启动D,如果D的启动模式为singleTop,那么栈内的情况仍然为ABCD;如果D的启动模式为standard,那么由于D被重新创建,导致栈内的情况就变为ABCD。
3、singleTask
android:launchMode="singleTask"
栈内复用模式,一种单实例模式。在任务栈里面只允许一个实例存在,假如02是singletask,栈里是:01 02 01 03 若此时开启02,则会复用这个已经存在的activity,并且把当前activity上面其他的activity从任务栈里清空!
相当于调用 onNewIntent+ClearTop
①. 设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的任务存在;如果存在这样的任务,它就会在这个任务中启动,否则就会在新任务中启动。因此,如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。
②. 如果设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例,如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity实例会位于任务的堆栈顶端中。
4、singleInstance
android:launchMode="singleInstance"
singleInstance的启动模式更加极端,开启新的activity,会给自己创建一个单独的任务栈,不管是从应用内部打开还是通过其他应用调用。TaskId(Android中每一个任务栈都有自己的一个ID,用TaskId表示)是单独的,已存在的则只需调用onNewIntent。应用场景:在整个手机操作系统里面只会有一个该activity的实例存在,如有道词典,金山词典等。所以多个应用程序共享这个activity的实例,有线程安全问题!例如闹铃提醒,将闹铃提醒与闹铃设置分离等。
由于某种原因,先简单介绍在这,日后再做详细代码演示。