在上一章节Android 面试题总结之Android 基础Broadcast Receiver(三) 我们讲了Broadcast Receiver基础知识。本节主要讲解Service相关基础知识,Service也是我们开发过程中经常使用到。
在阅读过程中有任何问题,请及时联系。如需转载请注明 fuchenxuan de Blog
本章系《Android 之美 从0到1 – 高手之路》Android基础Service 总结了Android 开发者面试比较常见的Service相关面试问题。希望对广大Android 开发者,有所帮助。
Service常见面试题
-
Service 是否在 main thread 中执行, service 里面是否 能执行耗时的操作?
默认情况,如果没有显示的指 servic 所运行的进程, Service 和 activity 是运 行在当前 app 所在进程的 main thread(UI 主线程)里面。
service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )
特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,让 service 在另 外的进程中执行
- 1
- 2
- 3
-
Activity 怎么和 Service 绑定,怎么在 Activity 中启动自 己对应的 Service?
Activity 通过 bindService(Intent service, ServiceConnection conn, int flags)跟 Service 进行绑定,当绑定成功的时候 Service 会将代理对象通过回调 的形式传给 conn,这样我们就拿到了 Service 提供的服务代理对象。
在 Activity 中可以通过 startService 和 bindService 方法启动 Service。一 般情况下如果想获取 Service 的服务对象那么肯定需要通过 bindService()方 法,比如音乐播放器,第三方支付等。如果仅仅只是为了开启一个后台任务那么 可以使用 startService()方法。 -
Service 的生命周期
Service 有绑定模式和非绑定模式,以及这两种模式的混合使用方式。不同 的使用方法生命周期方法也不同。
非绑定模式:当第一次调用 startService 的时候执行的方法依次为 onCreate()、onStartCommand(),当 Service 关闭的时候调用 onDestory 方 法。
绑定模式:第一次 bindService()的时候,执行的方法为 onCreate()、 onBind()解除绑定的时候会执行 onUnbind()、onDestory()。
上面的两种生命周期是在相对单纯的模式下的情形。我们在开发的过程中还 必须注意 Service 实例只会有一个,也就是说如果当前要启动的 Service 已经存 在了那么就不会再次创建该 Service 当然也不会调用 onCreate()方法。
一个 Service 可以被多个客户进行绑定,只有所有的绑定对象都执行了
onBind()方法后该 Service 才会销毁,不过如果有一个客户执行了 onStart() 方法,那么这个时候如果所有的 bind 客户都执行了 unBind()该 Service 也不会 销毁。Service 的生命周期图如下所示,帮助大家记忆。
-
什么是 IntentService?有何优点?
我们通常只会使用 Service,可能 IntentService 对大部分同学来说都是第 一次听说。那么看了下面的介绍相信你就不再陌生了。如果你还是不了解那么在 面试的时候你就坦诚说没用过或者不了解等。并不是所有的问题都需要回答上来的。
一、IntentService 简介
IntentService 是 Service 的子类,比普通的 Service 增加了额外的功能。
先看 Service 本身存在两个问题:
Service 不会专门启动一条单独的进程,Service 与它所在应用位于同一个进
程中;
Service 也不是专门一条新线程,因此不应该在 Service 中直接处理耗时的
任务;
二、IntentService 特征
会创建独立的 worker 线程来处理所有的 Intent 请求;
会创建独立的 worker 线程来处理 onHandleIntent()方法实现的代码,无需
处理多线程问题;
所有请求处理完成后,IntentService 会自动停止,无需调用 stopSelf()方法
停止 Service;
为 Service 的 onBind()提供默认实现,返回 null;
为 Service 的 onStartCommand 提供默认实现,将请求 Intent 添加到队列
中;
使用 IntentService
本人写了一个 IntentService 的使用例子供参考。该例子中一个
MainActivity 一个 MyIntentService,这两个类都是四大组件当然需要在清单 文件中注册。这里只给出核心代码:- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
-
Activity、Intent、Service 是什么关系
他们都是 Android 开发中使用频率最高的类。其中 Activity 和 Service 都是 Android 四大组件之一。他俩都是 Context 类的子类 ContextWrapper 的子类, 因此他俩可以算是兄弟关系吧。不过兄弟俩各有各自的本领,Activity 负责用户 界面的显示和交互,Service 负责后台任务的处理。Activity 和 Service 之间可 以通过 Intent 传递数据,因此可以把 Intent 看作是通信使者。
-
Service 和 Activity 在同一个线程吗?
对于同一 app 来说默认情况下是在同一个线程中的,main Thread (UI Thread)。 -
Service 里面可以弹吐司么
可以的。弹吐司有个条件就是得有一个 Context 上下文,而 Service 本身就是 Context 的子类,因此在 Service 里面弹吐司是完全可以的。比如我们在 Service 中完成下载任务后可以弹一个吐司通知用户。 -
什么是 Service 以及描述下它的生命周期。Service 有哪 些启动方法,有什么区别,怎样停用 Service?
在 Service 的生命周期中,被回调的方法比 Activity 少一些,只有 onCreate, onStart, onDestroy,
onBind 和 onUnbind。
通常有两种方式启动一个 Service,他们对 Service 生命周期的影响是不一样的。- 通过 startService
Service 会经历 onCreate 到 onStart,然后处于运行状态,stopService
的时候调用 onDestroy 方法。
如果是调用者自己直接退出而没有调用 stopService 的话,Service 会一直
在后台运行。 - 通过 bindService
Service 会运行 onCreate,然后是调用 onBind,这个时候调用者和 Service 绑定在一起。调用者退出了,Srevice 就会调用 onUnbind->onDestroyed 方 法。
所谓绑定在一起就共存亡了。调用者也可以通过调用 unbindService 方法来 停止服务,这时候 Srevice 就会调用 onUnbind->onDestroyed 方法。 需要注意的是如果这几个方法交织在一起的话,会出现什么情况呢? 一个原则是 Service 的 onCreate 的方法只会被调用一次,就是你无论多少次的 startService 又 bindService,Service 只被创建一次。
如果先是 bind 了,那么 start 的时候就直接运行 Service 的 onStart 方法,如 果先是 start,那么 bind 的时候就直接运行 onBind 方法。
如果 service 运行期间调用了 bindService,这时候再调用 stopService 的话,service 是不会调用 onDestroy 方法的,service 就 stop 不掉了,只能调用 UnbindService, service 就会被销毁
如果一个 service 通过 startService 被 start 之后,多次调用 startService 的 话,service 会多次调用 onStart 方法。多次调用 stopService 的话,service 只会调用一次 onDestroyed 方法。
如果一个 service 通过 bindService 被 start 之后,多次调用 bindService 的话, service 只会调用一次 onBind 方法。
多次调用 unbindService 的话会抛出异常。
- 通过 startService
-
在 service 的生命周期方法 onstartConmand()可不可以执行网络操作?如何在 service 中执行网络操作?
可以直接在 Service 中执行网络操作,在 onStartCommand()方法中可以执行网络操作 -
如何提高service的优先级?
Android 系统对于内存管理有自己的一套方法,为了保障系统有序稳定的运信,
系统内部会自动分配,控制程序的内存使用。当系统觉得当前的资源非常有限的时候,
为了保 证一些优先级高的程序能运行,就会杀掉一些他认为不重要的程序或者服务来释放内存。
这样就能保证真正对用户有用的程序仍然再运行。如果你的 Service 碰上了这种情况,多半会先被杀掉。
但如果你增加 Service 的优先级就能让他多留一会,
我们可以用 setForeground(true) 来设置 Service 的优先级。
为什么是 foreground ? 默认启动的 Service 是被标记为 background,当前运行的 Activity
一般被标记为 foreground,也就是说你给 Service 设置了 foreground 那么他就和正在运行的
Activity 类似优先级得到了一定的提高。当让这并不能保证你得 Service
永远不被杀掉,只是提高了他的优先级。 -
service 如何定时执行?
当启动service进行后台任务的时候,我们一般的 做法是启动一个线程,然后通过sleep方法来控制进行定时的任务,如轮询操作,消息推送。这样容易被系统回收。
service被回收是我们不能控制的,但是我们可以控制service的重启活动。在service的onStartCommand
方法中可以返回一个参数来控制重启活动
使用AlarmManager,根据AlarmManager的工作原理,alarmmanager会定时的发出一条广播,然后在自己的项目里面注册这个广播,重写onReceive方法,在这个方法里面启动一个service,然后在service里面进行网络的访问操作,当获取到新消息的时候进行推送,同时再设置一个alarmmanager进行下一次的轮询,当本次轮询结束的时候可以stopself结束改service。这样即使这一次的轮询失败了,也不会影响到下一次的轮询。这样就能保证推送任务不会中断 -
Service 的 onStartCommand 方法有几种返回值?各代表什么意思?
有四种返回值,不同值代表的意思如下:
START_STICKY:如果 service 进程被 kill 掉,保留 service 的状态为开始状态,但不保留递送的 intent 对象。随 后系统会尝试重新创建 service,由于服务状态为开始状态,所以创建服务后一定会调用 onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到 service,那么参数 Intent 将为 null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异常 kill 掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传 Intent。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异 常 kill 掉,系统会自动重启该服务,并将 Intent 的值传入。
**START_STICKY_COMPATIBILITY:**START_STICKY 的兼容版本,但不保证服务被 kill 后一定能重启。 -
Service 的 onRebind(Intent)方法在什么情况下会执行?
如果在 onUnbind()方法返回 true 的情况下会执行,否则不执行。 -
Activity 调用 Service 中的方法都有哪些方式?
Binder:
通过 Binder 接口的形式实现,当 Activity 绑定 Service 成功的时候 Activity 会在 ServiceConnection 的类 的 onServiceConnected()回调方法中获取到 Service 的 onBind()方法 return 过来的 Binder 的子类,然后通过对象调用方法。
Aidl:
aidl 比较适合当客户端和服务端不在同一个应用下的场景。Messenger:
它引用了一个Handler对象,以便others能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message的通信(即两个进程间可以通过Message进行通信),在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以与服务端通信了。一个Messeger不能同时双向发送,两个就就能双向发送了
这里画了一个粗浅的图帮助大家理解。
-
Service 如何给 Activity 发送 Message?
Service 和 Activity 如果想互发 Message 就必须使用使用 Messenger 机制。IntentService 适用场景
- IntentService 内置的是 HandlerThread 作为异步线程,每一个交给 IntentService 的任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理
- 正在运行的 IntentService 的程序相比起纯粹的后台程序更不容易被系统杀死,该程序的优先级是介于前台程序与纯后台程序之间的
关于Service相关基础知识点,本章节就先总结到这来。希望对大家有所帮助。