# 架构
# 基础知识
# 基础组件
界面组件:
- Activity
- Fragment
服务组件
- Service
广播组件
- BroadcastReceiver
数据组件
- ContentProvider
- ContentResolver
# Activity
Activiey 是一个界面容器,主要用于展示界面和与用户交互
# 生命周期:
//Activity 创建,完成初始化操作 | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
// Log.v (TAG,"Msg");//Verbose 观察值,Verbose 是冗长、啰嗦的意思,任何消息都会输出 | |
// Log.d (TAG,"Msg");//Debug 调试 | |
// Log.i (TAG,"Msg");//Info 信息,为一般提示性的消息 | |
// Log.w (TAG,"Msg");//Warn 可能会出问题,一般用于系统提示开发者需要优化 android 代码等场景 | |
// Log.e (TAG,"Msg");//Error 崩溃信息,一般用于输出异常和报错信息 | |
Log.i(TAG, "----onCreate----"); | |
} | |
// Activity 在最新任务列表中打开时候会走此方法 | |
@Override | |
protected void onRestart() { | |
super.onRestart(); | |
Log.i(TAG, "----onRestart----"); | |
} | |
// Activity 在 onCreate 或者 onRestart 之后执行 | |
@Override | |
protected void onStart() { | |
super.onStart(); | |
Log.i(TAG, "----onStart----"); | |
} | |
// 正在与用户交互的界面,前台活动 | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
Log.i(TAG, "----onResume----"); | |
} | |
// 被其他与用户交互的 Activity 部分覆盖 | |
@Override | |
protected void onPause() { | |
super.onPause(); | |
Log.i(TAG, "----onPause----"); | |
} | |
// 被其它与用户交互的 Activity 全部覆盖,可以做轻微重量级操作,如取消网络连接、注销广播接收器等 | |
@Override | |
protected void onStop() { | |
super.onStop(); | |
Log.i(TAG, "----onStop----"); | |
} | |
// Activity 销毁时候调用此方法,释放资源 | |
@Override | |
protected void onDestroy() { | |
super.onDestroy(); | |
Log.i(TAG, "----onDestroy----"); | |
} |
几种情况:
打开页面:
onCreate()
->onStart()
->onResume()
关闭页面:Resumed ->
onPause()
->onStep()
->onDestroy()
后台回收:销毁不会有时机处理,重建:
onStart()
->onRestoreInstanceState()
->onResume()
部分遮挡:Resumed ->
onPause()
遮挡恢复 ->onResume()
页面全遮挡:Resumed ->
onStop()
遮挡恢复:onRestart()
->onStart()
->onResume()
配置改变重建 Activity:Resumed ->
onSaveInstanceState()
->onPause()
- >onStop()
->onDestroy()
-onCteate()
->onStart()
->onRestoreInstanceState()
->onResume()
配置改变不重建 Activity:AndroidMainfest 配置 Activity 节点的 configChange 属性:
- local:语言改变
- fontSize:字体大小改变
- orientation:旋转屏幕
- keybordHidden:键盘显示隐藏
配置改变:onConfigurationChanged ()
Activity 四个状态:
- 运行状态:Activity 处于返回栈栈顶,此时最不可能被回收
- 暂停状态;不再处于任务栈栈顶,系统不会轻易回收
- 停止状态:不在栈顶且不可见,内存低时系统会回收
- 销毁状态:不在栈内,系统自动回收
# 启动模式
参考:https://juejin.cn/post/6844903781486821389
首先了解任务和返回堆栈:官方文档
用户在执行某项工作时与之互动的一系列 Activity 集合,这些 Activity 按照每个 Activity 打开的顺序排列在一个返回堆栈里。
Standard 默认启动模式
不设置 launchMode 属性默认是 Standard 启动模式,该模式的 Activity 启动就会在同一个任务栈创建一个新的实例,栈内可以存在多个实例。
例子:任务栈 A-B-C (C 是栈顶),如果 C 去启动一个 A,那么会重新创建一个实例 A,即最终结果为 A-B-C-A,这时我们返回的时候(按下返回键)顺序依次是 A-C-B-A
从 C 跳转到 A:
onPause-C
->onCreate-A
->onStart-A
->onResume-A
->onStop-C
-从 A 回退到 C:
onPause-A
->onRestart-C
->onStart-C
->onResume-C
->onStop-A
->onDestroy-A
home 或锁屏:
Resumed
->onPause
->onStop
home 回到 App:
onStop
->onRestart
->onStart
->onResunme
SingleTask 栈内复用启动模式
启动已在任务栈中的 Activity,则复用已经存在的 Activity 实例,调用该实例的
onNewInstant()
方法,若该实例不在栈顶,则将实例提到栈顶,在被调用的实例之上的实例出栈(销毁),如果实例不存在则创建一个实例加入当前栈常用于 APP 入口点
- A 在栈顶:A 启动 A:
onPause()
->onNewIntent
()->onResume
() - 不在栈顶:
- A->B B 启动 A:
Resumed-B
->onPause-B
->onNewIntent-A
->onRestart-A
->onStart-A
->onResume-A
->onStop-B
->onDestroy-B
- A ->B->C C 启动 A:
Resumed-C
->onDestroy-B
->onPause-C
->onNewIntent-A
->onRestart-A
->onStart-A
->onResume-A
->onStop-C
- >onDestroy-C
- A->B B 启动 A:
- A 在栈顶:A 启动 A:
SingleTop 栈顶复用启动模式
若调用的实例位于栈顶,则复用,调用
onNewTntent()
否则创建新的实例(类似于 Standard)- A 在栈顶,启动 A:
onPause()
->onNewIntent
()->onResume
() - A 不在栈顶:
- A->B,B 启动 A 后,A->B->A:
Resumed-B
->onPause-B
->onCreate-A
->onStart-A
->onResume-A
->onStop-B
- A->B->C,C 启动 A,A->B->C->
Resumed-C
->onPause-C
->onCreate-A
->onStart-A
->onResume-A
->onStop-C
- A->B,B 启动 A 后,A->B->A:
- A 在栈顶,启动 A:
SingleInstance 单例启动模式
全局单例,启动比较慢,切换效果不好,影响用户体验,用的不多,次启动模式的实例单独一个栈
# Intent 和 Intent 过滤器
Intent 是一个消息传递对象,基本用例:
- 启动 Activity
- 启动服务
- 传递广播
# 启动 Acitivity
Intent
用于描述要启动的 Activity
,将 Intent
对象传递给 stratActivity( )
可以启动新的 Activity
实例
如果希望启动的 Activity
完成后返回结果,使用 startActivityForResult( )
,在 Activity 的 onActivityResult( )
回调中,Activity 将结果作为单独的 Intent 对象接收
# 启动服务
Service 是没有用户界面的后台操作的组件,通过将 Intent
传递给 startService()
,启动服务执行一次性操作
如果服务旨在使用客户端 - 服务器接口,则通过将 Intent
传递给 bindService()
,可以从其他组件绑定到此服务。
# 传递广播
广播是任何应用均可接收的消息,系统根据系统事件传递广播,如网络断开与连接,充电等,通过将 Intent
传递给 sendBroadcast()
或 sendOrderedBroadcast()
,可以将广播传递给其他应用。
# 构建 Intent
Intent 中包含主要信息如下:
组件名称:要启动的组件名称(可选项),有组件名称为显示传递,没有名称是隐式。启动 Service 时组件名称一定要指定
操作:指定要执行的操作(查看、选取等)的字符串。对于广播 Intent,这是指已发生且正在报告的操作。操作会在很大程度上决定其余 Intent 的构成,特别是数据和 extra 中包含的内容。
数据:引用待操作数据和 / 或该数据 MIME 类型的 URI(
Uri
对象)。提供的数据类型通常由 Intent 的操作决定。例如,如果操作是ACTION_EDIT
,则数据应包含待编辑文档的 URI。使用
setDataAndType()
同时设置 URI 和 MIME 类型类别:一个包含应处理 Intent 组件类型的附加信息的字符串。可以将任意数量的类别描述放入一个 Intent 中,但大多数 Intent 均不需要类别。
Extra:携带完成请求操作所需的附加信息的键值对。正如某些操作使用特定类型的数据 URI 一样,有些操作也使用特定的 extra。
可以使用各种
putExtra()
方法添加 extra 数据,每种方法均接受两个参数:键名和值。您还可以创建一个包含所有 extra 数据的Bundle
对象,然后使用putExtras()
将Bundle
插入Intent
中。标志:标志在
Intent
类中定义,充当 Intent 的元数据。标志可以指示 Android 系统如何启动 Activity(例如,Activity 应属于哪个任务),以及启动之后如何处理(例如,Activity 是否属于最近的 Activity 列表)。
# Intent 实例
# 显式 Intent
显示 Intent 需要使用启动组件的名称(.class)
// 在 Activity 里执行,'this' 是 Context | |
// The fileUrl is a string URL, such as "http://www.example.com/image.png" | |
Intent downloadIntent = new Intent(this, DownloadService.class); | |
downloadIntent.setData(Uri.parse(fileUrl)); | |
startService(downloadIntent); |
Intent(Context, Class)
构造函数分别为应用和组件提供 Context
和 Class
对象。因此,此 Intent 将显式启动该应用中的 DownloadService
类。
# 隐式 Intent
隐式 Intent 指定能够在可以执行相应操作的设备上调用任何应用的操作。如果本应用无法执行该操作而其他应用可以,且希望用户选取要使用的应用,则使用隐式 Intent 非常有用。
例如,如果希望用户与他人共享你的内容,请使用 ACTION_SEND
操作创建 Intent,并添加指定共享内容的 extra。使用该 Intent 调用 startActivity()
时,用户可以选取共享内容所使用的应用。
:::warnning
** 注意:** 用户可能没有任何应用处理您发送到 startActivity()
的隐式 Intent。或者,由于配置文件限制或管理员执行的设置,可能无法访问应用。如果发生这样的情况,调用失败,应用也会崩溃。要验证 Activity 是否会接收 Intent,请对 Intent
对象调用 resolveActivity()
。如果结果为非空,则至少有一个应用能够处理该 Intent,并且可以安全调用 startActivity()
。如果结果为空,不要使用该 Intent。如有可能,您应停用发出该 Intent 的功能。以下示例说明如何验证 Intent 是否解析为 Activity。此示例没有使用 URI,但已声明 Intent 的数据类型,用于指定 extra 携带的内容。
:::
// Create the text message with a string | |
Intent sendIntent = new Intent(); | |
sendIntent.setAction(Intent.ACTION_SEND); | |
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); | |
sendIntent.setType("text/plain"); | |
// Verify that the intent will resolve to an activity | |
if (sendIntent.resolveActivity(getPackageManager()) != null) { | |
startActivity(sendIntent); | |
} |
# 接受隐式 Intent
要公布应用可以接收哪些隐式 Intent,请在清单文件中使用 <Intent-Filter>
过滤器之一传递时,系统才会将该 Intent 传递给应用组件。
显式 Intent 始终会传递给其目标,无论组件声明的 Intent 过滤器如何均是如此。
在 <Intent-Filter>
内部,可以使用以下三个元素中的一个或多个指定要接受的 Intent 类型:
<action>
在
name
属性中,声明接受的 Intent 操作。该值必须是操作的文本字符串值,而不是类常量。<data>
使用一个或多个指定数据 URI(
scheme
、host
、port
、path
)各个方面和 MIME 类型的属性,声明接受的数据类型。<category>
在
name
属性中,声明接受的 Intent 类别。该值必须是操作的文本字符串值,而不是类常量。
<activity android:name="ShareActivity"> | |
<intent-filter> | |
<action android:name="android.intent.action.SEND"/> | |
<category android:name="android.intent.category.DEFAULT"/> | |
<data android:mimeType="text/plain"/> | |
</intent-filter> | |
</activity> |
当接受类型为文本时,应用会接收 ACTION_SEND
的 Intent
过滤器一些实例
<activity android:name="MainActivity"> | |
<!-- This activity is the main entry, should appear in app launcher --> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
<activity android:name="ShareActivity"> | |
<!-- This activity handles "SEND" actions with text data --> | |
<intent-filter> | |
<action android:name="android.intent.action.SEND"/> | |
<category android:name="android.intent.category.DEFAULT"/> | |
<data android:mimeType="text/plain"/> | |
</intent-filter> | |
<!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> | |
<intent-filter> | |
<action android:name="android.intent.action.SEND"/> | |
<action android:name="android.intent.action.SEND_MULTIPLE"/> | |
<category android:name="android.intent.category.DEFAULT"/> | |
<data android:mimeType="application/vnd.google.panorama360+jpg"/> | |
<data android:mimeType="image/*"/> | |
<data android:mimeType="video/*"/> | |
</intent-filter> | |
</activity> |
ACTION_MAIN
操作指示这是主要入口点,且不要求输入任何 Intent 数据。CATEGORY_LAUNCHER
类别指示此 Activity 的图标应放入系统的应用启动器。如果<activity>
元素未使用icon
指定图标,则系统将使用<application>
元素中的图标。
这两个元素必须配对使用,Activity 才会显示在应用启动器中。