《Android开发进阶:从小工到专家》——个人读书笔记
第一章:Android 的构成基石——四大组件
- 四大组件:Activity、Service、ContentProvider和Broadcast
- Activity: 负责UI元素的加载与页面之间的跳转
- Service: 负责与UI无关的工作,如在后台执行耗时操作等
- ContentProvider: 负责数据的存储与共享,使得数据可以在多个应用之间共享
- Broadcast: 在各个组件、应用之间进行通信,简化了Android开发中的通信问题
1.1 Activity
-
Activity 的生命周期
1、onCreate() (创建)
自Activity的类时会默认生成该函数,在Activity第一次创建时被调用,主要完成Activity的初始化操作,比如:设置布局、初始化视图、绑定事件等。
2、onStart() (可见)
可见前的调用,当前依旧为不可见状态。
3、onResume() (获取焦点)
变为可见状态,执行完毕后Activity就会开始请求AMS渲染它所管理的视图。此时的Activity一定位于返回栈的栈顶,并且处于运行状态
4、onPause() (失去焦点)
即将从可见变为不可见。通常会将一些消耗CPU的资源释放掉,以及保存一些关键数据
5、onStop() (不可见)
完全不可见,区别于 onPause() 如:Dialog弹窗
6、onDestory() (销毁)
销毁前调用
7、onRestart() (重新可见)
Activity被重新启动了
注意:并不是各个时期的Activity都是可见的,只有在onResume()函数和onStop()函数之间的Activity是可见的。
1.1.1 Activity 的构成
视图会被设置给一个Window类,Window类中含有一个DecorView,这个DecorView才是整个窗口的顶级视图
Activity之下有一个PhoneWindow,它是Window的一个实现类。
1.1.2 Activity 的四种启动模式
- Android 内部使用通过回退栈来管理 Activity 实例的。
- 栈是一种后进先出的集合
- Activity 一共有四中启动模式:standard、singleTop、singleTask、singleInstance
- 1、standard——标准启动模式
如果 ActivityA 的启动模式为 standard,并且已经有一个 ActivityA 被启动,在该 ActivityA 中调用 startActivity 时会启动一个新的 ActivityA 实例
2、singleTop——栈顶复用模式
如果在栈顶就直接复用当前的 Activity,如果不在栈顶就重新创建一个新的 Activity 放到栈顶使用
3、singleTask——单任务模式
栈中只能有一个该 Activity 的实例,如果该 Activity 不在栈顶,则系统会销毁该 Activity 上方所有的 Activity,让该 Activity 位于栈顶
4、singleInstance——单实例模式
会在一个独立的任务中开启,并且此任务重有且只有这一个实例对象,也即是说该实例启动的其他 Activity 会自动运行与另一个任务中。当再次重启这个 Activity 实例时,会重用已经存在的任务和实例
1.1.3 FragmentActivity 与 Fragment
- 为了更好的运用越来越大的手机屏幕空间,Android3.0 引入了 Fragment。如果想要兼容更低版本的 Android系统,则需要引入v4包。
1.2 Service 与 AIDL
- Service 是 Android 中实现程序后台运行的解决方案,它既不运行在子线程之中也不运行在独立线程中,它同样运行在UI线程中,所以不能在 Service 中执行耗时操作
1.2.1 普通 Service
- Service 的生命周期:onCreate、onStartCommand、onDestory
- 调用Context的 startService() 来启动服务。服务启动之后会一直保持运行状态,直到 stopService() 或 stopSelf() 函数被调用
每个服务只会有一个实例,无论调用多少次startService(),只要调用一次stopService() 或 stopSelf()服务就会被停止
- Service 也需要在 AndroidManifest.xml 文件中进行注册
1.2.2 IntentService
- IntentService将用户的请求执行在一个子线程中,用户只需要覆写onHandleIntent函数,并且在该函数中完成自己的耗时操作即可。
- 适用于完成一些短期的耗时任务,因为它会在任务执行完毕后,调用 stopself 自我销毁
1.2.3 运行在前台的 Service
- Service 默认运行在后台,优先级较低,当系统内存不足时,会优先进行回收
- 要想 Service 一直保持运行状态,不被系统回收,可将 Service 运行在前台(例如通知栏中的消息显示)
1.2.4 AIDL(Android 接口描述语言)
- Android 提供的一种进程间通信(IPC)机制
1.3 Broadcast(广播)
- 一种广泛的运用在应用程序之间进行信息传输的机制
- 广播模式是一种典型的发布——订阅模式,即观察者模式
- 最大的特点:发送方并不关心结束方是否接收到了数据以及接收方如何进行数据的处理,收发双方完全解耦。
- Android 广播三要素:发送广播的 Broadcast、接收广播的 BroadcastReceiver 以及 传递信息的 Intent
- 广播的分类:普通广播、有序广播、本地广播
1.3.1 普通广播
- 完全异步,通过 sendBroadcast() 函数来发送,消息的传递效率比较高,但所有的 receivers(接收者) 的执行顺序不确定
- 缺点:接收者不能将消息的处理结果传递给下一个接收者,并且无法终止广播,直到没有与之匹配的广播接收器为止
注意:广播需要进行注册,分为两种:静态注册(在 AndroidManifest.xml 文件中进行注册)、动态注册(在代码中进行注册)
//动态注册示例:
private void registerMyBroadcast()
{
registerReceiver(new MyBroadcastReceiver()
, new IntentFilter(HELLO_ACTION))
}
如果是在 Activity 或者 Fragment 中进行动态测试,则需要在 onDestroy() 中实时的注销该广播
1.3.2 有序广播
- 通过 Context.sendOrderedBroadcast() 来发送,所有的广播接收器按照优先级依次进行信息的接收。
- 广播接收器的优先级可通过 receiver 的 inter-filter 中的 android:priority 属性来设置,数值越大优先级越高
- 接收到广播后通过setResult()函数将结果传递给下一个广播接收器,getResult()函数取得上个广播接收器返回的结果
1.3.3 本地广播
- supportV4包中的LocalBroadcastManager
- 在进程内进行信息的传输,安全性较高
函数 | 作用 |
---|---|
LocalBroadcastManager.getInstance(Context).registerReceiver(receiver, intentFilter) | 注册Receiver |
LocalBroadcastManager.getInstance(Context).unregisterReceiver(receiver) | 注销Receiver |
LocalBroadcastManager.getInstance(Context).sendBroadcast(new Intent(HELLO_ACTION)) | 发送异步广播 |
LocalBroadcastManager.getInstance(Context).sendBroadcastSync(new Intent()) | 发送同步广播 |
1.3.4 sticky 广播
- 通过 Context.sendStickyBroadcast() 来发送广播。使用此方式发送的广播会一直滞留,当有匹配此广播的广播接收器注册后,该广播接收器就会收到此条广播。
注意:使用此广播需要获得 BROADCAST_STICKY 权限
1.4 ContentProivider(外共享数据)
- 在 Android 中的作用就是对外共享数据。
- 优点:统一了数据的访问方式。
- 实际上是对 SQliteOpenHelper 的进一步封装,通过 Uri 映射来判断需选择操作数据库中的哪个表,并且进行增、删、改、查处理。
- Uri 代表要操作数据表的绝对路径,其中包含两个部分的信息,一是需要操作的 ContentProvider ,二是对 ContentProvider 中的哪个表进行操作
- Uri 包含四个部分:scheme + authority + path + id
- ContentProvider 的 scheme 已由 Android 固定设置为 content://
- Authority 是标志 ContentProvider 的唯一标识符,
- Path 是需要操作的数据库表
- id 是可选的关键字段
进一步划分:
[scheme:][//authority][path][?query][#fragment]
其中有下面几个规则:
path可以有多个,每个用/连接,比如
scheme://authority/path1/path2/path3?query#fragment
query参数可以带有对应的值,也可以不带,如果带对应的值用=表示,如:
scheme://authority/path1/path2/path3?id = 1#fragment,这里有一个参数id,它的值是1
query参数可以有多个,每个用&连接
scheme://authority/path1/path2/path3?id = 1&name = mingming&old#fragment
这里有三个参数:
参数1:id,其值是:1
参数2:name,其值是:mingming
参数3:old,没有对它赋值,所以它的值是null
在android中,除了scheme、authority是必须要有的,其它的几个path、query、fragment,它们每一个可以选择性的要或不要,但顺序不能变,比如:
其中"path"可不要:scheme://authority?query#fragment
其中"path"和"query"可都不要:scheme://authority#fragment
其中"query"和"fragment"可都不要:scheme://authority/path
"path","query","fragment"都不要:scheme://authority
等等……
关于 Uri 的详细结构划分,可参考这篇博客https://blog.csdn.net/harvic880925/article/details/44679239
- 通过ContentProvider机制,使得数据可以在各应用之间共享,并且为用户提供了同一的API接口,降低了用户的使用成本