一、Activity
的生命周期
1.1 生命周期图
1.2 可见状况图
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
被杀死并从头创立
剖析:当体系配置产生更改后,Activity会被毁掉,其onPause、onStop、onDestroy都会被调用,因为Activity是在反常状况下停止的,体系会调用onSaveInstanceState来保存当时Activity的状况(这个办法只会出现在Activity反常停止的状况下,正常状况下不会调用这个办法)。
当Activity
被从头创立后,体系会调用onRestoreInstanceState
,并且把Activity
毁掉时onSaveInstanceState
办法所保存的Bundle方针作为参数传递给onRestoreInstanceState
和onCreate
办法。
因此,能够经过onRestoreInstanceState
和onCreate
办法来判别Activity是否被重建了,假如被重建了,咱们就能够取出之前保存的数据并康复,从时序上来说,onRestoreInstanceState
的调用机遇在onStart
之后。
2.4 反常状况:资源内存不足
- 资源内存不足导致优先级低的Activity被杀死
Activity优先级从高到低能够分为以下三种:
前台Activity ——正在和用户交互的Activity,优先级最高。
可见但并非前台Activity——比方Activity中弹出一个对话框,导致Activity可见,可是坐落后台无法和用户交互。
后台Activity——已经被暂停的Activity,比方履行了onStop,优先级最低。
当体系内存不足时,体系就会依照上述优先级去杀死方针Activity
地点的进程,并在后续onSaveInstanceState
和onRestoreInstanceState
来存储和康复数据。
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 区别
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
- 简单的栈的进栈和出栈,先进后出
3.4 singleTop
- 栈顶复用形式意思就是说假如这个activity是在栈顶,再次发动这个activity就直接复用,不创立新的activity
3.5singleTask
- 与singleTop相似,只不过singleTop仅仅复用栈顶的元素,而singleTask能够复用栈内的所有元素,当发动的activity在栈内已经存在时,singleTask形式直接弹出方针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形式
四、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特点
第二步:在java 文件中写入逻辑代码
详细阐明
声明条件含:动作(Action)、类型(Category)、数据(Data)
五、 数据传递
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()
更多运用于单次传递、传递简单数据类型的运用场景
- 引证
- Activity关于生命周期一些问题的实践验证
- 陈词滥调-Activity