一、Activity
Activity 是一种可以包含用户界面的组件,主要用于和用户交互。一个应用程序中可以包含零个或多个活动。
1.1、Activity 的使用
(1)、继承 Activity,实现 Activity 的生命周期方法。
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
}
}
(2)、在 AndroidManifest.xml 文件中注册 Activity。
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
1.2、Activity的生命周期
1.2.1、典型情况下的生命周期
- onCreate(): 初始化
- onRestart(): Activity 重新启动,从不可见重新变为可见状态
- onStart(): 已经可见,但没有出现在前台,无法与用户交互,看不见
- onResume(): 可见,并在前台开始活动
- onPause(): 存储数据,停止动画等。需要不能太耗时
- onStop(): 做稍微重量级的回收操作,同样不能太耗时
- onDestroy(): 做一些回收工作和最终的资源释放
PS:onCreate 和 onDestory:是否存在
onStart 和 onStop:是否可见
onResume 和 onPause:是否位于前台
1.2.2、异常情况下的生命周期
情况一:资源相关的系统配置发生改变导致 Activity 被杀死并重新创建。
onSaveInstanceState(): 是用来保存当前 Activity 的状态,这个方法调用的时机是在 onStop() 之前,它和 onPause() 没有既定的时序关系,正常情况下不会被调用。
onRestoreInstanceState(): 将 Activity 销毁时 onSaveInstanceState() 方法所保存的 Bundle 对象作为参数同时传递给 onRestoreInstanceState() 和 onCreate() 方法。
- onSaveInstanceState() 和 onRestoreInstanceState() 方法中,系统自动为我们做了一定的恢复工作,默认保存当前Activity的视图结构,包括View的相关状态。
和 Activity 一样,每一个 View 都有 onSaveInstanceState() 和 onRestoreInstanceState() 这两个方法。关于保存和恢复 View 层次结构,系统的工作流程是这样的:首先Activity被意外终止是,Activity 会调用 onSaveInstanceState 去保存数据,然后 Activity 会委托 Window 去保存数据,接着 Window 再委托它上面的顶级容器去保存数据。顶层容器是一个 ViewGroup,一般来说是 DecorView。最后顶层容器再去一一通知它的子元素来保存数据,这样,整个数据保存的动作就完成了。
情况二:资源内存不足导致低优先级的 Activity 被杀死
Activity 按照优先级从高到低,可以分为三种:
- 前台 Activity——正在和用户交互的 Activity,优先级最高。
- 可见但非前台 Activity——比如 Activity 弹出了一个对话框,导致 Activity 可见但是位于后台无法和用户直接交互。
- 后台 Activity——已经被暂停的 Activity,比如执行了 onStop() 方法,优先级最低。
当系统内存不足时,系统就会按照上述优先级去杀死目标 Activity 所在的进程。如果一个进程中没有四大组件再执行,那么这个进程将很快被系统杀死,因此,一些后台工作不适合脱离四大组件而肚子运行在后台,这样进程很容易被杀死。比较好的方法是将后台工作放入 Service 中从而保证进程有一定的优先级,这样就不会轻易地被系统杀死。
如果当某项系统配置发生改变后,我们不想系统重新创建 Activity,可以给 Activity 指定 configChanges 属性。比如不想让 Activity 在屏幕旋转地时候重新创建,就可以给 configChanges 属性添加 orientation 这个值。如果想指定多个值,可以用“|”连接起来。
eg: android:configChanges = "orientation"
1.3、Activity的启动模式
1.3.1、四种启动模式
- standard 标准模式,默认模式。每次启动 Activity 都会重新创建一个新的实例,不管这个实例是否已经存在。在这个模式下,谁启动了这个Activity,那么这个 Activity 就运行在启动它的那个 Activity 所在的栈中。
- singleTop 栈顶复用模式。在这种模式下,如果 Activity 已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被毁掉,通过此方法的参数我们可以取出当前的请求的信息。
- singleTask 栈内复用模式。这是一种单实例模式,在这种模式下,只要 Activity 在一个栈中存在,那么多次启动此 Activity 都不会重新创建实例,和 singleTop 一样,系统也会自动调用其 onNewIntent。同时由于 singleTask 默认具有 clearTop 的效果,会导致栈内所有在被启动的 Activity 上面的 Activity 全部出栈,最终被启动的Activity留在栈顶。
- singleInstance 单实例模式。这是一种加强的 singleTask 模式,它除了具有 singleTask 模式的所有特性外,还加强了一点,那就是具有此种模式的 Activity 智能单独地位于一个任务栈中。
PS:任务栈:TaskAffinity,可以被翻译成任务相关性。这个参数标识了一个 Activity 所需要地任务栈的名字,默认情况下,所有 Activity 所需的任务栈的名字为应用的包名。我们也可以为每个 Activity 都单独指定 TaskAffinity 属性,这个属性值必须不能和包名相同,否则就相当于没有指定。TaskAffinity 属性主要和 singleTask 启动模式或者 allowTaskReparenting 属性配对使用,在其他情况下没有意义。任务栈分为前台任务栈和后台任务栈,后台任务栈中的 Activity 处于暂停状态,用户可以通过切换将后台任务栈再次调到前台。
1.3.2、指定启动模式
方法一: 通过 AndroidMenifest 为 Activity 指定启动模式。
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
方法二: 通过在Intent中设置标志位来为 Activity指 定启动模式。
Intent intent = new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
当两种同时存在时,以第二种为准;第一种方式无法直接为 Activity 设定 FLAG_ACTIVITY_CLEAR_TOP 标识,而第二种无法为 Activity 指定 singleInstance 模式。
1.3.3、Activity 的 Flags
标记位 | 含义 |
---|---|
FLAG_ACTIVITY_NEW_TASK | singleTask启动模式 |
FLAG_ACTIVITY_SINGLE_TOP | singleTop启动模式 |
FLAG_ACTIVITY_CLEAR_TOP | 具有此标记位的 Activity,当它启动时,在同一个任务栈中所有位于它上面的 Activity 都要出栈 |
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | 当某些情况下我们不希望用户通过历史列表回到我们的 ACtivity 的时候有用 |
1.4、Activity 的通讯
在同一个进程中的 Activity 之间的数据交互方式有以下几种:
- Intent
- 广播
1.4.1、借助 Intent 进行数据交互的几种方式
(1)、传递简单数据
通过 intent 的 putExtra() 和 get***Extra() 方法
MainActivity
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("msg1","dagedage");
intent.putExtra("msg2","woshixiaodi");
startActivity(intent);
SecondActivity
Intent intent = getIntent();
textView.setText(intent.getStringExtra("msg2") + "," + intent.getStringExtra("msg2"));
(2)、Bundle传递数据包
MainActivity
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putString("msg1","dagedage");
bundle.putString("msg2","woshixiaodi");
intent.putExtras(bundle);
startActivity(intent);
SecondActivity
Intent intent = getIntent();
Bundle b = intent.getExtras();
textView.setText(b.getString("msg1") + "," + b.getString("msg2"));
(3)、传递对象
public class UserMessage implements Serializable{
private String name;
private String age;
public UserMessage(String name, String age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
}
实现 Serializable 接口,可以对数据进行序列化。
MainActivity
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("UserMessage",new UserMessage("Chandelier","20"));
startActivity(intent);
SecondActivity
UserMessage um = (UserMessage)getIntent().getSerializableExtra("UserMessage");
textView.setText(um.getName() + ","+ um.getAge());
1.4.2、使用广播进行 Activity 之间的通讯
在要发送消息的 Activity 中发送广播,然后再要接收消息的 Activity 中定义广播接收者并注册,接收广播。
1.5、Activity 的启动过程
《Android开发艺术探索》第九章讲到了 Activity 的启动过程,非常复杂,经过一系列的交付委托,最终由 performLaunchActivity 方法最终完成了Activity 对象的创建和启动过程,并且 ActivityThread 通过 handleResumeActivity 方法来调用被启动的 Activity 的 onResume 这一生命周期方法。
handleLaunchActivity 源码:
private void handleLaunchActivity(ActivityClientRecord r,Intent customIntent){
...
if(localLOGV)
Slog.v(TAG,"Handling launch of " + r);
Activity a = performLaunchActivity(r,customIntent);
if(a != null){
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startNotResumed);
...
}
...
}
那么 performLaunchActivity 这个方法做了那些事情呢?
- 从 ActivityClientRecord 中获取待启动的 Activity 的组件信息
- 通过 Instrumentation 的 newActivity 方法使用类加载器创建 Activity 对象
- 通过 LoadedApk 的 makeApplication 方法来尝试创建 Application 对象。Application 创建完毕后,系统会通过 Instrumentation 的 callApplicationOnCreate 来调用 Application 的 onCreate 方法
- 创建 contextImpl 对象并通过 Activity 的 attach 方法来完成一些重要数据的初始化
- 调用 Activity 的 onCreate 方法