Activity
Activity Android 四大组件之一,代表着页面。它是整个视图的承载,从下层往上看分别贴附着 Window、ViewGroup、View。同时 Activity 接收用户的各种手势、触屏事件并进行派发。顺序从 Activity 开始到 View 结束:Activity->Window->ViewGroup->View。默认 Activity 的启动模式为标准模式,我们可以通过 launchMode 标签在清单配置文件中对此进行修改。
下面我们看 Activity 的生命周期,以及项目中经常出现的几个场景。
目录
- Activity 生命周期
- 场景一
- 场景二
- 场景三
- 场景四
Activity 生命周期
1> onCreate()
2> onStart()
3> onResume()
4> onPause()
5> onStop()
6> onRestart()
7> onDestory()
场景一
正在展现的 Activity 点击 Home 按键会那些生命周期函数?
会执行 onPause、onSaveInstanceState(非生命周期函数)
、onStop。当重新点击应用图标时会执行 onRestart、onStart、onResume。点击Back按键会执行 onPause、onStop、onDestory,当重新点击应用图标时会执行 onCreate、onStart、onResume。
场景二
现有两个 Activity 分别为 a,b。现在启动 a?a 启动 b?最后点击 back 键生命周期会如何调用?
1> Activity a 会调用 onCreate、onStart、onResume。
2> Activity a 启动 Activity b 两者的生命周期调用顺序如下:
onPause(a)、onCreate、onStart、onResume、onSaveInstanceState(a)、
onStop(a) 。
3> 点击 back 键 后会调用 onPause(b)、onRestart、onStart、onResume、
onStop(b)、onDestroy (b)。
//注:onSaveInstanceState 函数在 onPause 之后执行(不一定都会执行),例点击 back 按键。
场景三
现有三个 Activity 分别为 a1、a2、a3,其中 a2 为 singleInstance 模式,现在 a1 启动 a2,a2 启动 a3,此时呈现的页面为 a3,然后点击 back 按键页面会如何展示?
页面会回到 a1,如果再次点击 back 键,页面会回到 a2,再次点击应用会退出。
原因: Activity 由栈维护,栈的特点是先进后出,默认情况下 Activity 的启动模式为标准模式,所以 a1 和 a3 存放在同一个任务栈中,由于 a2 的启动模式为 singleInstance 所以 a2 会独占一个任务栈,也就是说当前应用现在有两个任务栈。第一当我们点击 back 键时 a3 所处的栈进行出栈操作,a3 销毁,a1 展示;再次点击 a1 销毁,当前栈销毁;再次点击 a2 销毁栈销毁,最终应用退出。
场景四
Activity 中 commit 一个 Fragment,两者分别会执行哪些生命周期函数。
1> 首先 Activity 会执行 onCreate 函数,随后 Fragment 会执行 onAttach、onCreate、onCreateView、onActivityCreated、onStart,随后 Activity 执行 onStart、随后 Activity 执行 onResume,随后 Fragment 执行 onResume,此时页面真正呈现同时可以进行操作。
2> 点击 Back 按键。首先 Fragment 执行 onPause、其次 Activity 执行 onPause;随后 Fragment 执行 onStop、Activity 执行 onStop;最后 Fragment 执行 onDestoryView、onDestory、onDetach,Activity 执行 onDestory 函数。
3> 点击 Home 按键。Fragment 执行 onPause,Activity 执行 onPause,Fragment 执行 onStop,Activity 执行 onStop 函数。
SingleTask 与 SingleInstance 区别?
Activity 由栈进行维护。SingleTask 模式的 Activity 可以与非 SingleInstance 模式的 Activity 在一个任务栈共存。 而 SingleInstance 模式的 Activity 则是独占一个 Activity 任务栈。同时使用场景不同:SingleTask 对应的 Activity 一般用于做应用主页面,SingleInstance 对应的 Activity 一般用于做广告页面。
如何启动其他应用的 Activity?
1> 创建 Intent 对象
Intent intent = new Intent();
2> 配置 Intent
//包名,包名+类名(全路径)
intent.setClassName("com.linxcool", "com.linxcool.PlaneActivity"));
3> 调用 startActivity 函数
Activity 的启动过程?
首先 Activity 的启动分为两种方式:
- 通过 launcher 进程启动
- 通过 startActivity 启动
前者:launcher 应用与 ActivityManagerServer(AMS)通信,告知 AMS 我要启动一个 Activity,系统 fork 出进程,执行 Java main 函数,创建 ActivityThread,实例化 Application,开启消息循环,创建 Activity,效验 Activity 合法性,启动 Activity,加载 xml 布局,执行 View 的 onMeasure、onLayout、onDraw 函数,最终视图呈现。
后者:由 Instrumentation 对象效验 Activity 的合法性,视情况创建 Activity 实例,回调 Activity 的 onCreate 函数,加载 xml 布局文件,执行 View 的 onMeasure、onLayout、onDraw 函数,最终视图呈现。
onNewIntent 调用时机?
一般常见于非标准启动模式的 Activity 中。举个例子:当 Activity 的启动模式为 SingleTask 时,同时任务栈中有此 Activity 的实例我们再次启动此 Activity 时,此 Activity 的实例不会重新创建,只会执行 onNewIntent 函数,然后执行 onRestart、onStart、onResume 函数。注:一般情况下 onNewIntent 函数是不会被触发的。。
总结:onNewIntent 在 onRestart 函数之前执行,大多数情况下并不会被触发,只有 Activity 的启动模式被我们主动修改了才会主动调用,同时此 Activity 实例必须在任务栈中已经存在。
Service
谈谈 Service 的生命周期?
Service 启动分为两种方式,分别为:
- startService
- bindService
前者生命周期:
onCreate->onStartCommand->onDestory
后者生命周期:
onCreate->onBind->onUnbind->onDestory
下面我们看两个场景:
场景一
一个 Service 通过 startService 启动后,调用 bindService 只会触发 onBind 函数,当被绑定的 Activity 销毁时只会调用 onUnbind 函数。我们也可以通过调用 unbindService 与此 Service 解除绑定。注:onDestory 函数并没有被调用,如果想要销毁此 Service 我们必须主动调用 stopService。
场景二
一个 Service 通过 bindService 启动后,再次调用 startService 只会调用 onStartCommand 函数,我们调用 stopService 函数并不会触发任何 Service 的生命周期函数,我们可以主动调用 unbindService 函数进行解绑,需要注意的是 onDestory 函数并不会执行。我们 Activity 被销毁只会触发 Unbind 函数,onDestory 函数同样不会被触发。如果想要真正的停止掉这个 Service 我们可以通过主动调用 stopService 函数。
Service 两种启动方式及区别
- startService
- bindService
前者:
生命周期函数执行顺序:onCreate->onStartCommand->onDestory
startService 函数调用两次 Service 并不会重新创建,只会执行 onStartCommand 函数,如果所在的 Activity 销毁并不会影响 Service 的正常运行,我们可以通过 stopService 函数来主动停止此 Service,一般用于 Activity 与 Service 通信较少的情况。
后者:
生命周期函数执行顺序:onCreate->onBind->onUnbind->onDestory
bindService 函数调用只会执行 onCreate、onBind 函数,当我们再次调用不会触发 Service 的任何生命周期函数。Service 的存亡与 Activity 绑定,换个说法就是当 Activity 销毁时 Service 会一并停止,我们也可以通过 unbindService 函数来主动停止此 Service,一般用于 Activity 与 Service 与 Activity 通信频繁场景。
一个 Activty 先 start 一个 Service 后,再 bind 时会回调什么方法?此时如何做才能回调 Service 的 onDestory 方法?
startService 会执行 onCreate、onStartCommand,此时如果调用 bindService 函数会调用 onBind 函数。我们先 unBindService 接着调用 stopService 就可以触发 Service 的 onDestory 函数,或者先调用 stopService 函数然后接着调用 unBindService 函数。
Service 与 Activity 如何通信?
1> 使用 bindService 的形式,bindService 函数中传入要 ServiceConnection 对象,从此对象的 onServiceConnected 函数中获取 Service 中的 IBinder 对象,进行通信。
2> 广播。
3>其他第三方库。
IntentService?
IntentService 继承自 Service 并处理异步请求的一个类,在 IntentService 内部有一个工作线程来处理耗时操作,当任务执行结束后 IntentService 会自动停止服务。如果 IntentService 启动多次,每一个耗时任务会以工作队列的形式在其 onHandleIntent 函数中回调执行,依次执行直到执行结束。
如何将 Service 改为前台服务?
前台服务是一种特殊的服务,它的特点是优先级很高,当系统内存比较低时 Android 系统也不会回收此类型服务。
举个例子:如果我们在 Service 中播放音乐,由于设备内存较低触发了 gc 突然 Service 被系统杀掉,但我们通过某种技术又将 Service 拉起重新进行音乐,可想而知这种体验是相对不好的。那么如何解决此问题发生呢?答案是将 Service 修改为前台服务。
如何开启?通过在 Service 的 onStartCommand 函数中调用 startForeground 函数。如何关闭?通过在 Service 的 onDestroy 函数中调用 stopForeground 函数。需要注意的是,如果我们将服务的优先级调整为前台,系统会强制在通知栏给用户一个提示。我们来看下 startForeground。
/**
* @param id The identifier for this notification as per
* {@link NotificationManager#notify(int, Notification)
* NotificationManager.notify(int, Notification)}; must not be 0.
* @param notification The Notification to be displayed.
*
* @see #stopForeground(boolean)
*/
public final void startForeground(int id, Notification notification) {
try {
mActivityManager.setServiceForeground(
new ComponentName(this, mClassName), mToken, id,
notification, 0);
} catch (RemoteException ex) {
}
}
- id 通知标识符
- notification 要展示在通知栏的具体对象
通过上面我们可以发现此函数接受两个参数一个是用于通知的对象(notification),一个是通知的一个标识。也就是说我们想要开启前台服务,就必须在通知栏强制弹出一个通知。
Broadcast
广播有几种形式?什么特点?
广播按照注册方式可以分为两种类型:
- 本地广播
- 系统广播(全局广播)
本地广播
本地广播的特点是广播由应用本身发送,发送的广播只能在应用内接受,其他应用无法收到本发出的广播,安全性更强,性能更高。
系统广播
系统广播可以被任意应用接收,性能和安全性相对本地广播而言较低。系统广播注册方式分为两种,分别为动态注册和静态注册。
广播按照顺序可以分为:
- 有序广播
- 无序广播
有序广播的特点是,广播的接收是有优先级的,优先级高的广播可以最先接受到广播。如果优先级高的广播接收器收到广播后进行了截断,则后续广播接收器无法继续收到广播。例:现在有 br1、br2、br3 三个广播接收器,其中 br1 优先级最高、br2 其次、br3 最低,如果此时 br1 接收到广播后调用了 abortBroadcast 函数,后续 br2 和 br3 则无法收到应用发出的有序广播。
其他种类的广播都可以成为无序广播,这里就不在做介绍。
广播的注册方式?
- 动态注册
- 静态注册
动态注册:
使用 Java 代码进行注册,一般在 onCreate 函数中进行注册,onDestory 函数进行解除注册。广播接收器的生命周期常伴随应用的生命周期,动态注册的广播可控性更强,优先级相对静态注册而言更高。
静态注册:
在 xml 中进行注册的广播,静态注册是常驻型 ,也就是说当应用程序关闭后,如果有信息广播来,程序仍会被系统调用运行,生命周期更长。例:监测开机广播。
总结:
广播按照注册方式可以分为两种分别为:动态注册,静态注册。按照广播类型可以分为:系统广播,应用内广播 or 普通广播和有序广播。动态注册的广播生命周期一般伴随应用的生命周期,优先级比较高;静态注册的广播反之。有序广播和无序广播的区别是有序广播是同步进行的,有先后顺序,无序广播反之。
ContentProvider
ContentProvider 存在的意义及作用?
为了在应用程序之间交换数据,Android 提供了ContentProvider,它是不同应用程序之间进行数据交换的标准 API。当一个应用程序需要把自己的数据暴露给其他应用程序使用时,该应用程序可以通过提供 ContentProvider 来实现。而其他应用程序需要使用这些数据时,不管提供数据的应用程序是否启动,我们都可以通过 ContentResolver 来操作 ContentProvider 暴露的数据。其中包括增加数据 insert、删除数据 delete、修改数据 update、查询数据 query 等。虽然大部分使用 ContentProvider 操作的数据都来自于数据库,但是也可以来自于文件,如:SharedPreferences、XML 或网络等其他存储方式。
简而言之,ContentProvider 作为 Android 四大组件之一,它的诞生主要是给不同应用提供内容访问。ContentProvider 封装了数据的跨进程传输,我们可以直接使用 getContentResolver() 拿到 ContentResolver 进行数据的增删改查。
完~
喜欢有帮助的话: 双击、评论、转发,动一动你的小手让更多的人知道!关注 Android_YangKe