大厂内部面试题:Android四大组件之一Service系列

Service-服务,Android四大组件之一,偷鸡摸狗必备功能之一。和Activity最大的区别就是多用户不可见。

#Service系列问题

##Service本地服务及生命周期详解

1.1 什么是Service,为什么使用Service

与Activity相对应的就是Service(服务)了,Activity在明,Service在暗。Service 是一个可以在后台执行长时间运行的服务,对用户不可见。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行(注意:对于国内手机厂商来说,有可能切换到后台后立即就被kill,特别被压倒后台并且手机熄屏后)。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行

1.2 Android中跨进程的通信方式

源码:AndroidIPC

1.通过Binder绑定,在Binder中实现一系列的方法对Service进行操作:

2.添加一个继承Binder的内部类,并添加相应的逻辑方法 .
/** * 继承自Binder */ class MyBinder : Binder() { var bindService: BindService? = null; fun start() { bindService!!.startDownload() } fun stop() { bindService!!.stopDownload(); } }

3.重写Service的onBind方法,返回我们刚刚定义的那个内部类实例
class BindService : Service() { var binder: MyBinder? = null; override fun onCreate() { super.onCreate() binder = MyBinder(); binder!!.bindService = this; } fun startDownload() { Log.d(“BindService”, “startDownload”); } fun stopDownload() { Log.d(“BindService”, “stopDownload”); } override fun onBind(intent: Intent): IBinder { //TODO(“Return the communication channel to the service.”) return binder!! } }

4.重写ServiceConnection,onServiceConnected时调用逻辑方法 绑定服务
/** * Connection是Binder中Android进程间通信的桥梁,将IBinder对象在进程间传输 */ class BindConnection(internal var context: Context) : ServiceConnection { var binder: MyBinder? = null; var button: Button? = null; override fun onServiceConnected(name: ComponentName, service: IBinder) { this.binder = service as MyBinder Log.d(“BindService”, “onServiceConnected”) button!!.text=“绑定成功”; } override fun onServiceDisconnected(name: ComponentName) { Toast.makeText(context, “断开链接”, Toast.LENGTH_SHORT).show() } }

5.启动时进行绑定
class Main3Activity : AppCompatActivity() { var connection: BindConnection? = null; override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main3) findViewById(R.id.btn).setOnClickListener { bindIBinderService(); } findViewById(R.id.btn2).setOnClickListener { connection!!.binder!!.start(); connection!!.binder!!.stop(); } } fun bindIBinderService() { connection = BindConnection(this); connection!!.button = findViewById(R.id.btn) as Button; bindService(Intent(this, BindService::class.java), connection, Context.BIND_AUTO_CREATE); } override fun onDestroy() { super.onDestroy() unbindService(connection); } }

6.BroadCastReceive Android必读之BroadcastReceive基础

7.Messenger 在client与Server端互相绑定Messenger可以实现两端互相通信

8.在Activity中实现Messenger,绑定时将对象传到Service
/** * * @param messenger Activity中的Messenger,将此Messenger传递到Service中, * 从而使Service可以通过Messenger向Activity发送消息 * @param connection 链接的桥梁 */ class Main4Activity : AppCompatActivity() { var connection: MessengerConnection? = null; var handler = Handler(object : Handler.Callback { override fun handleMessage(msg: Message?): Boolean { when (msg!!.what) { 1 -> { Log.d(“Main4Activity”, “Receive Msg”); } else -> { } } return true; } }); var messenger: Messenger = Messenger(handler); override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main3) findViewById(R.id.btn).setOnClickListener { bindMessengerService(); } findViewById(R.id.btn2).setOnClickListener { var message: Message = Message.obtain(); message.what = 1; connection!!.messenger!!.send(message); } } fun bindMessengerService() { connection = MessengerConnection(this); connection!!.button = findViewById(R.id.btn) as Button; var intent = Intent(this, MessengerService::class.java); intent.putExtra(“Messenger”, messenger); bindService( intent, connection as ServiceConnection, Context.BIND_AUTO_CREATE ); } override fun onDestroy() { super.onDestroy() unbindService(connection as ServiceConnection); } }

9.在Service中获取Activity中的Messenger并且把自己的Messenger通过Connect传递给Activity
class MessengerService : Service() { var handler = Handler(object : Handler.Callback { override fun handleMessage(msg: Message?): Boolean { when (msg!!.what) { 1 -> { Log.d(“MessengerService”, “startDownload”); } 2 -> { Log.d(“MessengerService”, “stopDownload”); } 3, 4 -> {//同时符合3,4 } else -> { } } return true; } }); var messenger: Messenger = Messenger(handler); var activityMessenger: Messenger? = null; override fun onCreate() { super.onCreate() } override fun onBind(intent: Intent): IBinder { activityMessenger = intent.getParcelableExtra(“Messenger”); var message: Message = Message.obtain(); message.what = 1; activityMessenger!!.send(message); return messenger.binder } }

10.AIDL

1.3 介绍源码中Binder机制

答:Binder是进程间通信的具体实现,实现了IBinder接口,在BindService中接收Service中onBind(Intent intent)返回的Binder对象,通过这个Binder对象就可以对Service进行操作。这个Binder对象可以是继承自Binder类型的new出来的实例,也可以是aidl生成的AIDL.Stub对象

1.4 IntentService与Service的区别

答:IntentService是继承并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统的Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们手动去控制或stopSelf()。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。推荐阅读:Android必读之IntentService

1.5 Service 是否在 main thread 中执行, service 里面是否 能执行耗时的操作?

默认情况,如果没有显示的指 service 所运行的进程, Service 和 activity 是运 行在当前 app 所在进程的 main thread(UI 主线程)里面。service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,让 service 在另 外的进程中执行

        <service
                android:name=".aidl.AidlService"
                android:enabled="true"
                android:process=":AidlService"
                android:exported="true">

android:enabled service能否被系统实例化,默认为true

android:exported service能否被隐式调用 默认为true

android:process 是否在单独的进程中,如果没有设置值,则表明此service与UI线程在同一个进程中,并且是在主线程中。如果设置值以冒号“:”开头,则表明此service是App私有的,不能被共享;如果设置的值以小写字母开头,则表明此service是可以被系统共享的。

1.6 Service的生命周期

Service 有绑定模式和非绑定模式,以及这两种模式的混合使用方式。不同 的使用方法生命周期方法也不同。

非绑定模式:当第一次调用 startService 的时候执行的方法依次为 onCreate()、onStartCommand(),当 Service 关闭的时候调用 onDestory 方 法。

绑定模式:第一次 bindService()的时候,执行的方法为 onCreate()、 onBind()解除绑定的时候会执行 onUnbind()、onDestory()。

上面的两种生命周期是在相对单纯的模式下的情形。我们在开发的过程中还 必须注意 Service 实例只会有一个,也就是说如果当前要启动的 Service 已经存 在了那么就不会再次创建该 Service 当然也不会调用 onCreate()方法。

1.7 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 后一定能重启。

1.8 Service 的 onRebind(Intent)方法在什么情况下会执行?

如果在 onUnbind()方法返回 true 的情况下会执行,否则不执行。

    /**
     * Called when all clients have disconnected from a particular interface
     * published by the service.  The default implementation does nothing and
     * returns false.
     *
     * @param intent The Intent that was used to bind to this service,
     * as given to {@link android.content.Context#bindService
     * Context.bindService}.  Note that any extras that were included with
     * the Intent at that point will <em>not</em> be seen here.
     *
     * @return 注意这里:Return true if you would like to have the service's
     * {@link #onRebind} method later called when new clients bind to it.
     */
    public boolean onUnbind(Intent intent) {
        return false;
    }

1.9 Activity 调用 Service 中的方法都有哪些方式?

源码:AndroidIPC

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不能同时双向发送,两个就就能双向发送了

之后还会不断的更新Android面试题,而且我还收集了一份关于Android架构进阶的资料,高级架构技术进阶脑图、Android开发面试专题资料等等。

如果你对这份资料感兴趣的话,可以自行前往 Github 领取

喜欢本文的话,不妨顺手给我点个赞、评论区留言或者转发支持一下呗~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值