一、Activity的生命周期

1.1 生命周期图

【Android -- 四大组件】Activity

1.2 可见状况图

【Android -- 四大组件】Activity

1.3 状况解释

生命周期办法 效果 阐明
onCreate 正在被创立 activity 被创立时调用,一般在这个办法中进行活动的初始化作业,如设置布局作业、加载数据、绑定控件等。
onRestart 正在从头发动 这个回调代表了 Activity 由彻底不行见从头变为可见的进程,当 Activity 阅历了 onStop() 回调变为彻底不行见后,假如用户回来原 Activity,便会触发该回调,并且紧接着会触发 onStart() 来使活动从头可见。
onStart 正在被发动 阅历该回调后,Activity 由不行见变为可见,但此刻处于后台可见,还不能和用户进行交互。
onResume 已经可见 已经可见的 Activity 从后台来到前台,能够和用户进行交互。
onPause 正在中止 当用户发动了新的 Activity ,本来的 Activity 不再处于前台,也无法与用户进行交互,并且紧接着就会调用 onStop() 办法,但假如用户这时马上按回来键回到原 Activity ,就会调用 onResume() 办法让活动从头回到前台。并且在官方文档中给出了阐明,不允许在 onPause() 办法中履行耗时操作,因为这会影响到新 Activity 的发动。
onStop 即将中止 这个回调代表了 Activity 由可见变为彻底不行见,在这里能够进行一些稍微重量级的操作。需求留意的是,处于 onPause() 和 onStop() 回调后的 Activity 优先级很低,当有优先级更高的运用需求内存时,该运用就会被杀死,那么当再次回来原 Activity 的时分,会从头调用 Activity 的onCreate()办法。
onDestroy 即将被毁掉 来到了这个回调,阐明 Activity 即将被毁掉,应该将资源的收回和开释作业在该办法中履行。

二、 生命周期剖析

2.1 常见状况下生命周期的回调

状况 回调
第一次发动 onCreate() -> onStart() -> onResume()
从 A 跳转到 B A_onPause() -> B_onCreate() -> B_onStart() -> B_onResume() -> A_onStop()
从 B 再次回到 A B_onPause() -> A_onRestart() -> A_onStart() -> A_onResume() -> B_onStop()
用户按 home 键 onPause() -> onStop()
按 home 键后回到运用 onRestart() -> onStart() -> onResume()
用户按电源键屏保 onPause() -> onStop()
用户按电源键亮屏 onRestart() -> onStart() -> onResume()
用户按 back 键回退 onPause() -> onStop() -> onDestroy()

2.2 关于生命周期常见问题

问题 回调
由活动 A 发动活动 B时,活动 A 的 onPause() 与 活动 B 的 onResume() 哪一个先履行? 活动 A 的 onPause() 先履行,活动 B 的 onResume() 办法后履行
规范 Dialog 是否会对生命周期产生影响 没有影响
全屏 Dialog 是否会对生命周期产生影响 没有影响
主题为 Dialog 的 Activity 是否会对生命周期产生影响 有影响,与跳转 Activity 一样

2.3 反常状况:资源配置相关

  • 资源相关的体系配置产生改动导致Activity被杀死并从头创立
【Android -- 四大组件】Activity

剖析:当体系配置产生更改后,Activity会被毁掉,其onPause、onStop、onDestroy都会被调用,因为Activity是在反常状况下停止的,体系会调用onSaveInstanceState来保存当时Activity的状况(这个办法只会出现在Activity反常停止的状况下,正常状况下不会调用这个办法)。

Activity被从头创立后,体系会调用onRestoreInstanceState,并且把Activity毁掉时onSaveInstanceState办法所保存的Bundle方针作为参数传递给onRestoreInstanceStateonCreate办法。

因此,能够经过onRestoreInstanceStateonCreate办法来判别Activity是否被重建了,假如被重建了,咱们就能够取出之前保存的数据并康复,从时序上来说,onRestoreInstanceState的调用机遇在onStart之后。

2.4 反常状况:资源内存不足

  • 资源内存不足导致优先级低的Activity被杀死

Activity优先级从高到低能够分为以下三种:

  • 前台Activity ——正在和用户交互的Activity,优先级最高。

  • 可见但并非前台Activity——比方Activity中弹出一个对话框,导致Activity可见,可是坐落后台无法和用户交互。

  • 后台Activity——已经被暂停的Activity,比方履行了onStop,优先级最低。

当体系内存不足时,体系就会依照上述优先级去杀死方针Activity地点的进程,并在后续onSaveInstanceStateonRestoreInstanceState来存储和康复数据。

2.5 反常状况下的处理

  在产生反常状况后,用户再次回到 Activity,原 Activity 会从头树立,原已有的数据就会丢失,比方用户操作改动了一些特点值,重建之后用户就看不到之前操作的成果,在反常的状况下如何给用户带来好的体验,有两种办法。

2.5.1 数据保存

  第一种就是体系提供的 onSaveInstanceState 和 onRestoreInstanceState 办法,onSaveInstanceState 办法会在 Activity 反常毁掉之前调用,用来保存需求保存的数据,onRestoreInstanceState 办法在 Activity 重建之后获取保存的数据。

  在活动反常毁掉之前,体系会调用 onSaveInstanceState,能够在 Bundle 类型的参数中保存想要的信息,之后这个 Bundle 方针会作为参数传递给 onRestoreInstanceState 和 onCreate 办法,这样在从头创立时就能够获取数据了。

  关于 onSaveInstanceState 与 onRestoreInstanceState 办法需求留意的一些问题:

  1. onSaveInstanceState 办法的调用机遇是在 onStop 之前,与 onPause 没有固定的时序联系。而 onRestoreInstanceState 办法则是在 onStart 之后调用。

  2. 正常状况下的活动毁掉并不会调用这两个办法,只有当活动反常毁掉并且有时机重现展现的时分才会进行调用,除了资源配置的改动外,activity 因内存不足被毁掉也是经过这两个办法保存数据。

  3. 在 onRestoreInstanceState 和 onCreate 都能够进行数据康复作业,可是根据官方文档主张采用在 onRestoreInstanceState 中去康复。

  4. 在 onSaveInstanceState 和 onRestoreInstanceState 这两个办法中,体系会默许为咱们进行必定的康复作业,具体地讲,默许完成会为布局中的每个 View 调用相应的 onSaveInstanceState() 办法,让每个视图都能提供有关本身的应保存信息。Android 结构中几乎每个小部件都会根据需求完成此办法,以便在重建 Activity 时主动保存和康复付 UI 所做的任何可见更改。例如 EditText 中的文本信息、ListView 中的翻滚方位等。也能够经过 android:saveEnabled 特点设置为 “false” 或经过调用 setSaveEnabled() 办法显式阻止布局内的视图保存其状况,一般不会将该特点停用,除非想要以不同办法康复 Activity IU 的状况。

  5. onSveInstanceState() 常见的触发场景有:反正屏切换、按下电源键、按下菜单键、切换到别的 Activity 等;onRestoreInstanceState() 常见的触发场景有:反正屏切换、切换语言等等。

2.5.2 防止重建

  在默许状况下,资源配置改动会导致活动的从头创立,可是能够经过对活动的 android:configChanges 特点的设置使活动防止从头被创立。

特点值 含义
mcc SIM 卡仅有标识IMSI(世界移动用户标识码)中的国家代码,由三位数字组成,我国为:460,这里标识 mcc 代码产生了改动
mnc SIM 卡仅有标识 IMSI(世界移动用户标识码)中的运营商代码,有两位数字组成,我国移动 TD 体系为 00 ,我国联通为 01,电信为 03,此项标识 mnc 产生了改动
locale 设备的本地方位产生了改动,一般指的是切换了体系语言
touchscreen 触摸屏产生了改动
keyboard 键盘类型产生了改动,比方用户运用了外接键盘
keyboardHidden 键盘的可访问性产生了改动,比方用户调出了键盘
navigation 体系导航办法产生了改动
screenLayout 屏幕布局产生了改动,很可能是用户激活了别的一个显现设备
fontScale 体系字体缩放份额产生了改动,比方用户选择了个新的字号
uiMode 用户界面形式产生了改动,比方敞开夜间形式 -API8 新增加
orientation 屏幕方向产生改动,比方旋转了手机屏幕
screenSize 当屏幕尺寸信息产生改动(当编译选项中的 minSdkVersion 和 targeSdkVersion 均低于 13 时不会导致 Activity 重启 ) API 13 新增加
smallestScreenSize 设备的物理尺寸产生改动,这个和屏幕方向没联系,比方切换到外部显现设备 -API13 新增加
layoutDirection 当布局方向产生改动的时分,正常状况下无法修改布局的 layoutDirection 的特点 -API17 新增加

能够在特点中声明多个配置值,办法运用 “|” 字符分割这些配置值。

三、发动形式

3.1 区别

【Android -- 四大组件】Activity

3.2 设置

1. 在 AndroidMainifest 设置

<activity
android:launchMode="发动形式"
//特点
//standard规范形式
//singleTop栈顶复用形式
//singleTask栈内复用形式
//singleInstance单例形式
//如不设置Activity的发动形式默许为**规范形式standard)**
</activity>

2.经过Intent设置标志位

Intent inten = new Intent (ActivityA.this,ActivityB.class);
intent,addFlags(Intent,FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

3.3 standard

  • 简单的栈的进栈和出栈,先进后出
    【Android -- 四大组件】Activity

3.4 singleTop

  • 栈顶复用形式意思就是说假如这个activity是在栈顶,再次发动这个activity就直接复用,不创立新的activity
    【Android -- 四大组件】Activity

3.5singleTask

  • 与singleTop相似,只不过singleTop仅仅复用栈顶的元素,而singleTask能够复用栈内的所有元素,当发动的activity在栈内已经存在时,singleTask形式直接弹出方针activity之上的所有元素,讲方针元素置于栈顶。

【Android -- 四大组件】Activity

activity1是singleTask形式,当再次发动activity1的时分,栈内已经存在方针activity(activity1),则弹出activity1之上的所有activity,讲方针置于栈顶。

运用场景
程序主界面,咱们肯定不希望主界面被多创立,并且在主界面退出的时分退出整个App是最好的设想。
消耗体系资源的Activity:关于那些及其消耗体系资源的Activity,咱们能够考虑将其设为singleTask形式,削减资源消耗(在创立阶段消耗资源的状况,个人理解-。+)

3.6 singleInstance

在该形式下,咱们会为目创立一个新的Task栈,将方针Activity放入新的Task,并让方针Activity取得焦点。新的Task有且只有这一个Activity实例。 假如已经创立过方针Activity实例,则不会创立新的Task,而是将曾经创立过的Activity唤醒(对应Task设为Foreground状况)。
为了便利理解,也为了与standard形式融会贯通,我在下图中activity1和activity2运用的是standard形式,而activity3运用的是singleInstance形式

【Android -- 四大组件】Activity

四、Intent

在Android中,Activity的发动是经过Intent来表达的,Intent是组件之间通信的前言,专门提供组件互相调用的相关信息

4.1 显现发动

第一种:class 跳转

// 1. 实例化显式Intent & 经过结构函数接收2个参数
// 参数1 = Context:发动活动的上下文,一般为当时Activity 
// 参数2 = Class:是指定要发动的方针活动
Intent intent = new Intent(Activity.this,Activity2.class);
// 2. 经过Activity类的startActivity()履行该意图操作(接收一个Intent方针)
// 将构建好的Intent方针传入该办法就可发动方针Activity
startActivity(intent);

第二种:包名.类名跳转

Intent intent = new Intent();
intent.setClassName(FirstActivity.this,"com.xiaozeng.launchapplication.SecondActivity");
startActivity(intent);

第三种:ComponentName跳转

Intent intent = new Intent()
ComponentName componentName = new ComponentName(FirstActivity.this,SecondActivity.class);
intent.setComponent(componentName);
startActivity(intent);

4.2 隐式发动

隐式发动并不明确指出想要发动的哪一个活动,而是指定了一系列的action和category等信息,然后由体系去剖析这个Intent,并帮咱们找出合适的活动去发动

第一步:在AndroidManifest.xml文件中 界说action和category特点

【Android -- 四大组件】Activity

第二步:在java 文件中写入逻辑代码

【Android -- 四大组件】Activity

详细阐明
声明条件含:动作(Action)、类型(Category)、数据(Data)

【Android -- 四大组件】Activity

五、 数据传递

5.1 运用办法

  • startActivity();
  • startActivityForResult();
  • 自界说办法 actionStart(), 最佳数据传值办法
  • 经过 Bundle 传递数据

5.2 可传递的数据类型

  • 8 种基本数据类型(boolean、 byte、 char、 short、 int、 long、 float、 double)、String
  • Intent、Bundle
  • Serializable方针、Parcelable及其对应数组、CharSequence 类型
  • ArrayList,泛型参数类型为:、<? Extends Parcelable>

5.3 startActivity

// 在MainActivity中界说如下代码 
button1.setOnClickListener(new OnClickListener() {
	@Override
	public void onClick(View v) {
			Intent intent = new 
			Intent(MainActivity.this,TwoActivity.class);
	        //在Intent方针傍边增加一个键值对
		    intent.putExtra("key","value");                 
		    startActivity(intent);
	}
});
// 在TwoActivity中界说如下代码
public class TwoActivity extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		button2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				//取得从上一个Activity傍边传递过来的Intent方针
				Intent intent = getIntent();
				//从Intent傍边根据key取得value
				if (intent != null) {
					String value = intent.getStringExtra("key");
				}
			}
		});
	}
}

5.4 startActivityForResult

	button1.setOnClickListener(new OnClickListener() {
		@Override
		public void onClick(View v) {
             Intent intent = new Intent(MainActivity.this,TwoActivity.class);
             intent.putExtra("key", "value");
             // 第二个参数是恳求码,只要是一个仅有值
             startActivityForResult(intent, 1234);
		}
	});
 	// 因为咱们是运用startActivityForResult()办法来发动TwoActivity的,在TwoActivity被毁掉之后会回调上一个活动的onActivityResult()办法
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        switch (requestCode) {
            case 1234:
                if (resultCode == RESULT_OK) {
					//接收方针
					//Bundle bundle = data.getExtras();
                    //AddressBean addressBean = (AddressBean) bundle.getSerializable(Constant.ADDRESSBEAN);
                    String returnedData = intent.getStringExtra("key1");
                }
                break;
            default:
        }
    }
public class TwoActivity extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//接收从MainaActivity传递的数据
		Intent intent = getIntent();
		if (intent != null) {
			String value = intent.getStringExtra("key");
		}
		button2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
			    //传递方针
				//Intent intent = new Intent();
		        //Bundle bundle = new Bundle();
		        //bundle.putSerializable(Constant.ADDRESSBEAN, addressArray.get(position));
		        //intent.putExtras(bundle);
		        //setResult(RESULT_OK, intent);
		        //finish();
				Intent intent = new Intent();
				intent.putExtra("key1","value two activity");
				// 专门用于向上一个活动回来数据。第一个参数用于向上一个活动回来成果码,一般只运用RESULT_OK或RESULT_CANCELED这两个值
				setResult(RESULT_OK, intent);
				finish();
			}
		});
	}
}

5.5 自界说办法 actionStart(); 最佳数据传值办法

button1.setOnClickListener(new OnClickListener() {
	@Override
	public void onClick(View v) {
			/*最佳数据传值办法:调用在下个activity自界说的办法*/
            TwoActivity.actionStart(MainActivity.this, "data1", "data2");
	}
});
public class TwoActivity extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	}
    //最佳数据传值办法
	public static void actionStart(Context context, String data1, String data2) {
		Intent intent = new Intent(context, TwoActivity.class);
		intent.putExtra("param1", data1);
		intent.putExtra("param2", data2);
		context.startActivity(intent);
	}
}

5.6 经过 Bundle 传递数据

// 1. 数据传递
// a. 创立Intent方针(显现Intent)
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);     
// b. 创立bundle方针
Bundle bundle = new Bundle();
// c. 放入数据到Bundle
bundle.putString("name", "carson");
bundle.putInt("age", 28);
// d. 将Bundle放入到Intent中
intent.putExtras(bundle);
// e. 发动Activity
startActivity(intent);
// 2. 数据取出(在被发动的Activity中)
// a. 获取用于发动SecondActivit的Intent
Intent intent = getIntent();
// b. 经过Intent获取bundle
Bundle bundle = intent.getExtras();
// c. 经过bundle获取数据传入相应的键名,就可得到传来的数据
// 留意数据类型 与 传入时保持一致
String nameString = bundle.getString("name");
int age = bundle.getInt("age");

5.7 putExtra和Bundle

Bundle意为捆绑的意思,更多适用于:

  • 接连传递数据
    若需完成接连传递:Activity A -> B -> C;若运用putExtra(),则需写两次intent = A->B先写一遍 + 在B中取出来 & 再把值从头写到Intent中再跳到C;若运用 Bundle,则只需取出 & 传入 Bundle方针即可

  • 可传递的值:方针
    putExtra()无法传递方针,而Bundle则可经过putSerializable传递方针

// 如传递User类的方针
public class User implements Serializable {
    ...
}
// 传递时
User user = new User();
Intent intent = new Intent(MyActivity.this,OthereActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("user", user);
intent.putExtras(bundle);

putExtra() 更多运用于单次传递、传递简单数据类型的运用场景

  • 引证
  1. Activity关于生命周期一些问题的实践验证
  2. 陈词滥调-Activity