Activity 是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操做。 每一个 Activity 都会得到一个用于绘制其用户界面的窗口。窗口一般会充满屏幕,但也可小于屏幕并浮动在其余窗口之上。android
一个应用一般由多个彼此松散联系的 Activity 组成。 通常会指定应用中的某个 Activity 为“主”Activity,即首次启动应用时呈现给用户的那个 Activity。 并且每一个 Activity 都可启动另外一个 Activity,以便执行不一样的操做。浏览器
自定义一个Activity,继承Activity,在onCreate()
生命周期方法中setContentView(layoutId)
(layoutId
是自定义的布局文件),而后在清单文件中注册该Activity。安全
启动 Activity 的方法:startActivity(Intent intent)
app
结束 Activity 的方法:finish()
、finishActivity(requestCode)
iview
三组生命周期方法ide
onCreate()
~ onDestroy()
onStart()
~ onStop()
onResume()
~ onPause()
数据回收和恢复工具
onSaveInstanceState(Bundle outState)
在Activity销毁前保存重要数据,在onPause方法以后被调用onRestoreInstanceState(Bundle savedInstanceState)
恢复数据,在onResume()方法以前调用onCreate(Bundle savedInstanceState)
这里也能够恢复数据方法 | 说明 | 是否能过后终止 | 后接 |
---|---|---|---|
onCreate() | 首次建立 Activity 时调用。 您应该在此方法中执行全部正常的静态设置 — 建立视图、将数据绑定到列表等等。 系统向此方法传递一个 Bundle 对象,其中包含 Activity 的上一状态,不过前提是捕获了该状态(请参阅后文的保存 Activity 状态)。始终后接 onStart()。 | 否 | onStart() |
onRestart() | 在 Activity 已中止并即将再次启动前调用。始终后接 onStart() | 否 | onStart() |
onStart() | 在 Activity 即将对用户可见以前调用。若是 Activity 转入前台,则后接 onResume(),若是 Activity 转入隐藏状态,则后接 onStop()。 | 否 | onResume() 或 onStop() |
onResume() | 在 Activity 即将开始与用户进行交互以前调用。 此时,Activity 处于 Activity 堆栈的顶层,并具备用户输入焦点。始终后接 onPause()。 | 否 | onPause() |
onPause() | 当系统即将开始继续另外一个 Activity 时调用。 此方法一般用于确认对持久性数据的未保存更改、中止动画以及其余可能消耗 CPU 的内容,诸如此类。 它应该很是迅速地执行所需操做,由于它返回后,下一个 Activity 才能继续执行。若是 Activity 返回前台,则后接 onResume(),若是 Activity 转入对用户不可见状态,则后接 onStop()。 | 是 | onResume() 或 onStop() |
onStop() | 在 Activity 对用户再也不可见时调用。若是 Activity 被销毁,或另外一个 Activity(一个现有 Activity 或新 Activity)继续执行并将其覆盖,就可能发生这种状况。若是 Activity 恢复与用户的交互,则后接 onRestart(),若是 Activity 被销毁,则后接 onDestroy()。 | 是 | onRestart() 或 onDestroy() |
onDestroy() | 在 Activity 被销毁前调用。这是 Activity 将收到的最后调用。 当 Activity 结束(有人对 Activity 调用了 finish()),或系统为节省空间而暂时销毁该 Activity 实例时,可能会调用它。 您能够经过 isFinishing() 方法区分这两种情形。 | 是 | 无 |
特别介绍:onNewIntent()
,该方法在要启动的Activity已经存在,而且不须要从新建立时调用。布局
显式启动:单元测试
//方式1
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
//方式2
Intent intent = new Intent();
ComponentName componentName = new ComponentName(this,SecondActivity.class);
intent.setComponent(componentName);
startActivity(intent);
//方式3
Intent intent = new Intent();
intent.setClassName("com.hdib","com.hdib.SecondActivity");
startActivity(intent);
// 方式4
startActivityForResult(intent,requestCode);
复制代码
隐式启动(详见 Intent匹配规则):测试
//案例1(发送电子邮件)
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
复制代码
Activity A 的 onPause() 方法执行。
Activity B 的 onCreate()、onStart() 和 onResume() 方法依次执行。(Activity B 如今具备用户焦点。)
而后,若是 Activity A 在屏幕上再也不可见,则其 onStop() 方法执行。
Launcher
组件向ActivityManagerService
发送一个启动MainActivity
的进程间通讯请求。ActivityManagerService
首先将要启动的MainActivity
信息保存起来,而后再向Launcher发送一个进入终止状态的进程间通讯请求。Launcher
组件进入终止状态后就会向ActivityManagerService
发送一个已经进入终止状态的进程间通讯请求,以便ActivityManagerService
能够继续执行MainActivity
的启动。ActivityManagerService
发现用于运行MainActivity
的应用程序进程不存在,所以会先启动一个新的应用程序进程。ActivityManagerService
发送一个启动完成的进程间通讯请求,以便ActivityManagerService
能够继续执行MainActivity
的启动。ActivityManagerService
将第二步保存起来的MainActivity
信息发送第四步建立的新的应用程序进程,以便将MainActivity
启动起来。launchMode | Description |
---|---|
standard | 默认模式,多实例模式。系统老是会启动一个新的Activity来知足要求——即使已经存在该Activity。 而且它老是归属于调用 startActivity() 将其启动的那个task。 |
singleTop | 共同点:同上。 不一样点:当该Activity已经被启动而且位于目标Task的栈顶时,就经过 onNewIntent() 方法将Intent传递给该Activity,而不是新启动一个Activity。 |
singleTask | 这样的Activity在一个Task中只能有一个。 若是该Activity已经启动,那么将经过 onNewIntent() 方法将Intent传递给它,并清空栈顶Activity,同时将包含剩余Activity的整个Task移到前台。这种模式容许与其余Activity在相同的task中,只是要保证该Activity在Task中只有一个就能够了。 |
singleInstance | 单实例模式,永远单独在一个task中。启动该Activity时,若是Activity实例不存在,必定会从新建立task并将该Activity实例放入其中。 |
Flag | Description |
---|---|
FLAG_ACTIVITY_NEW_TASK |
等同于singleTask 模式。如下flag须要与这个flag一块儿用。FLAG_ACTIVITY_CLEAR_TASK :清除栈中其余Activity。FLAG_ACTIVITY_TASK_ON_HOME :新启动的Activity放在task栈中Launcher的上面。FLAG_ACTIVITY_MULTIPLE_TASK :阻止系统恢复一个现有的task,也就是每次都新启动一个task。FLAG_ACTIVITY_LAUNCH_ADJACENT :仅用于分屏多窗口模式,新启动的Activity显示在启动它的Activity旁边,若是须要建立现有Activity的新实例,应同时设置FLAG_ACTIVITY_MULTIPLE_TASK 。 |
FLAG_ACTIVITY_BROUGHT_TO_FRONT |
launchMode中设置singleTask 时会自动加上这个标志。若是该Activity已经被建立,并且存在于某个task中,此时另一个task启动该Activity,系统会自动清理该Activity之上的全部Activity |
FLAG_ACTIVITY_SINGLE_TOP |
等同于singleTop 模式。 |
FLAG_ACTIVITY_CLEAR_TOP |
若是要启动的Activity已经在栈中,那么须要清除在该Activity之上的全部Activity,并经过onNewIntent() 方法将Intent传递给该Activity |
FLAG_ACTIVITY_PREVIOUS_IS_TOP |
相似于FLAG_ACTIVITY_CLEAR_TOP |
FLAG_ACTIVITY_NO_HISTORY |
该Activity将不会被保存在History Stack 中。 |
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
该Activity不会被放在系统最近启动的Activity列表中。 如进程列表截图中不会有这个页面(会获取上一个页面的截图) 按home键回到桌面后,在点击桌面图标应用从新回到前台时,也不会显示这个页面,而是显示上一个页面。 |
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED |
不管Activity的目标task是新task仍是现有task,都会处于task的上端。 通常要 FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 标识配合使用,不过该标识 API 21 之后过期,FLAG_ACTIVITY_NEW_DOCUMENT 取代之。该Activity启动时,若是目标栈中已经有该Activity,那么清除其上面的全部Activity。 |
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY |
系统自动设置,从历史记录中启动 |
FLAG_ACTIVITY_NO_USER_ACTION |
可以使onUserLeaveHint() 回调不执行,该方法用于指示用户将要离开,Activity会退出前台。 |
FLAG_ACTIVITY_REORDER_TO_FRONT |
若是Activity已经在History stack中,则调整顺序使其到栈顶。 |
FLAG_ACTIVITY_NO_ANIMATION |
无动画启动Activity |
FLAG_ACTIVITY_FORWARD_RESULT |
该Flag不能和startActivityForResult() 同时使用,表示不接受onActivityResult() 回调。该Flag启动的Activity若是调用了 setResult() 方法,那么回调结果不会传递给启动它的Activity,而是传递给前一个Activity。 |
FLAG_ACTIVITY_MATCH_EXTERNAL |
Android P Developer Priview中加入 |
设置后,若是设备上没有可以处理该intent的app,那么将会启动一个instant app来进行处理。 | |
FLAG_ACTIVITY_RETAIN_IN_RECENTS |
默认状况下经过FLAG_ACTIVITY_NEW_DOCUMENT 启动的activity在关闭以后,task中的记录会相对应的删除。若是为了可以从新启动这个activity你想保留它,就可使用这个flag,最近的记录将会保留在接口中以便用户去从新启动。接受该flag的activity可使用autoRemoveFromRecents 去复写这个request或者调用Activity.finishAndRemoveTask() 方法。 |
FLAG_DEBUG_LOG_RESOLUTION |
在处理这个intent的时候,将会打印相关建立日志。 |
FLAG_RECEIVER_NO_ABORT |
若是这是一个有序广播,不容许接受者终止这个广播,它仍然可以传递给下面的接受者。 |
FLAG_RECEIVER_REGISTERED_ONLY |
若是设置了这个flag,当发送广播的时,动态注册的接受者才会被调用,在AndroidManifest.xml 里定义的Receiver 是接收不到这样的Intent的。 |
FLAG_RECEIVER_REPLACE_PENDING |
若是设置了的话,ActivityManagerService 就会在当前的系统中查看有没有相同的intent还未被处理,若是有的话,就由当前这个新的intent来替换旧的intent,因此就会出如今发送一系列的这样的 Intent 以后,中间有些 Intent 有可能在你尚未来得及处理的时候,就被替代掉了的状况。 |
FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS |
设置以后,广播将对instant app中的广播接收器可见。默认不可见。 |
FLAG_GRANT_READ_URI_PERMISSION |
读权限,容许组件从Intent中包含的URI里边读取数据。 |
FLAG_GRANT_WRITE_URI_PERMISSION |
写权限,容许组件向Intent中包含的URI里边写入数据。 |
FLAG_FROM_BACKGROUND |
该Intent是一个后台操做。 |
startActivityForResult()
由于 activity 的不少启动模式或 flag 具备清除栈内已有 activity 的效果,清除实际是调用的系统的 remove task 方法,该方法会使得被清除的 activity 执行 onDestory()
等方法销毁,同时若是被销毁的 activity 是被其余 activity 用startActivityForResult()
方法启动的,销毁时会给它的启动 activity 传递回去 result cancel 事件,启动方 activity 的onActivityResult()
方法会被调用,这个时候容易出现咱们意料以外的问题。
从 Task 的角度看,Android 认为不一样 Task 之间的 Activity 是不能传递数据的,所以若是启动用startActivityForResult()
方式启动新 activity,而新启动的 activity 和当前 activity 不在同一个栈时,当前 activity 的onActivityResult()
方法回立刻被回调,而且传递回result cancel
事件,能够从 AMS 打出的 log 上看到有这么一句:
WARN/ActivityManager(67): Activity is launching as a new task, so cancelling activity result.
就是这个意思,下面startActivityForResult()
的注释也进行了说明。
putExtra("key","value");
String str = getStringExtra(“key”);
复制代码
Bundle bundle = new Bundle();
bundle.putString("key","value");
intent.putExtras(bundle);
String str = getIntent().getExtras().getString("key");
复制代码
显式启动,直接用ComponentName
定位到肯定的组件并启动。
隐式启动,与三个因素有关:Category
、Action
、Data
。Extras
和Flag
只在目标组件已经选择好准备启动时才起做用。这些因素中的一个组合就是一个intent-filter
。
隐士启动匹配规则:至少有一个intent-filter
匹配成功,才能启动该组件。
几个注意事项:
Intent
中若是不指定Category
那么系统会默认添加CATEGORY_DEFAULT
。intent-filter
中action
为空,那么全部的Intent
都不能与之匹配。intent-filter
中有非空action
,那么Intent
中的action
必须为空,或是其子集才能与之匹配。Intent
的data
没有指定MIME
也没有指定URI
,此时只有intent-filter
中也不指定相应值才能匹配。Intent
的data
没有指定MIME
(也没法从URI推断出来),但有指定URI
,此时只有intent-filter
中也不指定MIME
,且URI
符合要求,才能匹配。Intent
的data
指定了MIME
,但没有指定URI
,此时只有intent-filter
中也指定MIME
且不指定URI
,才能匹配。Intent
的data
指定了MIME
,也指定了URI
,此时只有intent-filter
中也指定MIME
且URI
符合要求,才能匹配。ComponentName
指定包名和全类名,直接定位到要启动的组件。比如一我的的名字,能够直接定位到这我的。
Category
从大的方向上对Intent进行了分类。比如国籍,能够定位到这我的所在的国家,不能定位到这我的。
通常来讲,CATEGORY_DEFAULT
能够解决全部问题,Intent默认指定的也是该值。
如下是标准Category。
Category Name | Description |
---|---|
CATEGORY_DEFAULT |
目标方对于默认的Action是一个可选项。 |
CATEGORY_BROWSABLE |
目标方能正确显示连接所指向的内容,如图片、网页等。可以被浏览器安全调用的组件必须制定该值。 |
CATEGORY_TAB |
目标方能够在已有的TabActivity内部做为一个Tab使用。 |
CATEGORY_ALTERNATIVE |
目标方是能正确打开用户正在浏览的数据的一个选择。 |
CATEGORY_SELECTED_ALTERNATIVE |
目标方能正确打开用户已经选择的数据。 |
CATEGORY_LAUNCHER |
目标方能够经过点击Launcher中的图标来启动。 |
CATEGORY_INFO |
目标方用于提供包信息,当应用没有CATEGORY_LAUNCHER 组件时使用。 |
CATEGORY_HOME |
Launcher,系统启动后启动的第一个组件。 |
CATEGORY_PREFERENCE |
该组件是选项卡 |
CATEGORY_TEST |
测试使用(通常状况不使用) |
CATEGORY_CAR_DOCK |
手机被插入汽车底座(硬件)时启动目标方。 |
CATEGORY_DESK_DOCK |
手机被插入桌面底座(硬件,柜台展现样机)时启动目标方。 |
CATEGORY_LE_DESK_DOCK |
|
CATEGORY_HE_DESK_DOCK |
|
CATEGORY_CAR_MODE |
目标方可在车载环境下使用。 |
CATEGORY_APP_MARKET |
用来指定目标方是应用市场。 |
CATEGORY_VR_HOME |
目标方做为VR启动页面。 |
如下Category
,之后可能不兼容。
Category Name | Description |
---|---|
CATEGORY_VOICE |
目标方能与用户进行语音交互,可能不须要UI展现。 |
CATEGORY_LEANBACK_LAUNCHER |
目标方将在LEANBACK 模式时启动。leanback,指能够像看电视同样向后靠着看,形容清晰度高。 |
CATEGORY_CAR_LAUNCHER |
目标方将在CAR_LAUNCHER 模式时启动。 |
CATEGORY_LEANBACK_SETTINGS |
目标方将做为LEANBACK 模式中一个设置页面。 |
CATEGORY_DEVELOPMENT_PREFERENCE |
该组件是一个开发者选项卡。 |
CATEGORY_EMBED |
能够运行在父Activity容器内。 |
CATEGORY_MONKEY |
目标方能够被monkey或者其余的自动测试工具执行。 |
CATEGORY_UNIT_TEST |
单元测试使用。 |
CATEGORY_SAMPLE_CODE |
Sample组件 |
CATEGORY_OPENABLE |
用来指示一个GET_CONTENT 意图但愿只有ContentResolver.openInputStream 可以打开URI。 |
CATEGORY_TYPED_OPENABLE |
用来打开文件或流,使用openFileDescriptor 、openTypedAssetFileDescriptor 、getStreamTypes 方法。 |
CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST |
用于测试时,做为framework层测试代码使用。 |
CATEGORY_APP_BROWSER |
和ACTION_MAIN 一块儿使用,用来指定目标方是浏览器应用。 |
CATEGORY_APP_CALCULATOR |
和ACTION_MAIN 一块儿使用,用来指定目标方是计算器应用。 |
CATEGORY_APP_CALENDAR |
和ACTION_MAIN 一块儿使用,用来指定目标方是日历应用。 |
CATEGORY_APP_CONTACTS |
和ACTION_MAIN 一块儿使用,用来指定目标方是联系人应用。 |
CATEGORY_APP_EMAIL |
和ACTION_MAIN 一块儿使用,用来指定目标方是邮件应用。 |
CATEGORY_APP_GALLERY |
和ACTION_MAIN 一块儿使用,用来指定目标方是图库应用。 |
CATEGORY_APP_MAPS |
和ACTION_MAIN 一块儿使用,用来指定目标方是地图应用。 |
CATEGORY_APP_MESSAGING |
和ACTION_MAIN 一块儿使用,用来指定目标方是短信应用。 |
CATEGORY_APP_MUSIC |
和ACTION_MAIN 一块儿使用,用来指定目标方是音乐应用。 |
启动Activity使用。
Action | Description |
---|---|
ACTION_MAIN |
应用程序入口。 |
ACTION_VIEW |
显示数据给用户。 |
ACTION_ATTACH_DATA |
指明附加信息。 |
ACTION_EDIT |
显示可编辑数据。 |
ACTION_PICK |
显示可选择数据。 |
ACTION_CHOOSER |
选择器。 |
ACTION_GET_CONTENT |
用于获取信息。 |
ACTION_DIAL |
显示打电话面板。 |
ACTION_CALL |
直接打电话。 |
ACTION_SEND |
直接发短信。 |
ACTION_SENDTO |
选择联系人发短信。 |
ACTION_ANSWER |
应答电话。 |
ACTION_INSERT |
插入数据。 |
ACTION_DELETE |
删除数据。 |
ACTION_RUN |
运行数据。 |
ACTION_SYNC |
同步数据。 |
ACTION_PICK_ACTIVITY |
选择Activity。 |
ACTION_SEARCH |
搜索。 |
ACTION_WEB_SEARCH |
Web搜索。 |
ACTION_FACTORY_TEST |
工厂测试入口点。 |
系统广播使用。
Action | Description |
---|---|
ACTION_TIME_TICK |
系统时间,1分钟发一次广播 |
ACTION_TIME_CHANGED |
系统时间经过设置发生了变化。 |
ACTION_TIMEZONE_CHANGED |
时区改变。 |
ACTION_BOOT_COMPLETED |
系统启动完毕。 |
ACTION_PACKAGE_ADDED |
新的应用程序apk包安装完毕。 |
ACTION_PACKAGE_CHANGED |
现有应用程序apk包改变。 |
ACTION_PACKAGE_REMOVED |
现有应用程序apk包被删除。 |
ACTION_PACKAGE_RESTARTED |
应用重启。 |
ACTION_PACKAGE_DATA_CLEARED |
应用数据被清理。 |
ACTION_PACKAGES_SUSPENDED |
应用被挂起。 |
ACTION_PACKAGES_UNSUSPENDED |
应用被解除挂起状态,恢复正常。 |
ACTION_UID_REMOVED |
用户id被删除。 |
ACTION_BATTERY_CHANGED |
电池信息变化,包括电量变化。 |
ACTION_POWER_CONNECTED |
外接电源,如充电宝。 |
ACTION_POWER_DISCONNECTED |
外接电源拔出。 |
ACTION_SHUTDOWN |
设备关机。 |
data属性有如下5部分组成:
android:scheme
android:host
android:port
android:path
android:mimeType
data的前四个属性构成了URI(scheme://host:port/path
),mimeType设置了数据的类型。
官方文档。 深刻理解Android内核设计思想.林学森 SDK源码。