android绑定服务和非绑定服务器,绑定服务概览  |  Android 开发者  |  Android Developers...

绑定服务是客户端-服务器接口中的服务器。借助绑定服务,组件(例如 Activity)可以绑定到服务、发送请求、接收响应,以及执行进程间通信 (IPC)。绑定服务通常只在为其他应用组件提供服务时处于活动状态,不会无限期在后台运行。

本文介绍如何创建绑定服务,包括如何绑定到来自其他应用组件的服务。如需了解有关一般服务的更多信息(例如:如何通过服务传送通知、如何将服务设置为在前台运行等),请参阅服务文档。

基础知识

绑定服务是

绑定到已启动服务

如服务文档中所述,您可以创建同时具有已启动和已绑定两种状态的服务。换言之,您可以通过调用

如果您确实允许服务同时具有已启动和已绑定状态,那么服务启动后,系统不会在所有客户端均与服务取消绑定后销毁服务,而必须由您通过调用

尽管您通常应实现 例如,音乐播放器可能认为,让其服务无限期运行并同时提供绑定很有用处。如此一来,Activity 便可启动服务来播放音乐,并且即使用户离开应用,音乐播放也不会停止。然后,当用户返回应用时,Activity 便能绑定到服务,重新获得播放控制权。

如需详细了解为已启动服务添加绑定时的服务生命周期,请参阅管理绑定服务的生命周期部分。

客户端通过调用 onServiceConnected() 方法包含一个

您可以将多个客户端同时连接到某项服务。但是,系统会缓存

当最后一个客户端取消与服务的绑定时,系统会销毁该服务(除非还通过

在实现绑定服务的过程中,最重要的环节是定义

创建绑定服务

创建提供绑定的服务时,您必须提供

如果服务是供您的自有应用专用,并且在与客户端相同的进程中运行(常见情况),您应当通过扩展

如果服务只是您自有应用的后台工作器,应优先采用这种方式。您不使用这种方式创建接口的唯一一种情况是:其他应用或不同进程占用了您的服务。

如需让接口跨不同进程工作,您可以使用

这是执行进程间通信 (IPC) 最为简单的方式,因为

Android 接口定义语言 (AIDL) 会将对象分解成原语,操作系统可通过识别这些原语并将其编组到各进程中来执行 IPC。以前采用

如需直接使用 AIDL,您必须创建用于定义编程接口的 .aidl 文件。Android SDK 工具会利用该文件生成实现接口和处理 IPC 的抽象类,您随后可在服务内对该类进行扩展。

注意:大多数应用不应使用 AIDL 来创建绑定服务,因为它可能需要多线程处理能力,并可能导致更为复杂的实现。因此,AIDL 并不适合大多数应用,本文也不会阐述如何将其用于您的服务。如果您确定自己需要直接使用 AIDL,请参阅 AIDL 文档。

扩展 Binder 类

如果您的服务仅供本地应用使用,且无需跨进程工作,您可以实现自有

注意:只有当客户端和服务处于同一应用和进程内(最常见的情况)时,此方式才有效。例如,对于需要将 Activity 绑定到在后台播放音乐的自有服务的音乐应用,此方式非常有效。

以下为设置方式:

在您的服务中,创建可执行以下某种操作的 包含客户端可调用的公共方法。

返回当前的

返回由服务承载的其他类的实例,其中包含客户端可调用的公共方法。

在客户端中,从

注意:服务和客户端必须在同一应用内,这样客户端才能转换返回的对象并正确调用其 API。服务和客户端还必须在同一进程内,因为此方式不执行任何跨进程编组。

例如,以下服务可让客户端通过

Kotlin

class LocalService : Service() {

// Binder given to clients

private val binder = LocalBinder()

// Random number generator

private val mGenerator = Random()

/** method for clients */

val randomNumber: Int

get() = mGenerator.nextInt(100)

/**

* Class used for the client Binder. Because we know this service always

* runs in the same process as its clients, we don't need to deal with IPC.

*/

inner class LocalBinder : Binder() {

// Return this instance of LocalService so clients can call public methods

fun getService(): LocalService = this@LocalService

}

override fun onBind(intent: Intent): IBinder {

return binder

}

}Java

public class LocalService extends Service {

// Binder given to clients

private final IBinder binder = new LocalBinder();

// Random number generator

private final Random mGenerator = new Random();

/**

* Class used for the client Binder. Because we know this service always

* runs in the same process as its clients, we don't need to deal with IPC.

*/

public class LocalBinder extends Binder {

LocalService getService() {

// Return this instance of LocalService so clients can call public methods

return LocalService.this;

}

}

@Override

public IBinder onBind(Intent intent) {

return binder;

}

/** method for clients */

public int getRandomNumber() {

return mGenerator.nextInt(100);

}

}

LocalBinder 为客户端提供 getService() 方法,用于检索 LocalService 的当前实例。这样,客户端便可调用服务中的公共方法。例如,客户端可调用服务中的 getRandomNumber()。

点击按钮时,以下 Activity 会绑定到 LocalService 并调用 getRandomNumber():

Kotlin

class BindingActivity : Activity() {

private lateinit var mService: LocalService

private var mBound: Boolean = false

/** Defines callbacks for service binding, passed to bindService() */

private val connection = object : ServiceConnection {

override fun onServiceConnected(className: ComponentName, service: IBinder) {

// We've bound to LocalService, cast the IBinder and get LocalService instance

val binder = service as LocalService.LocalBinder

mService = binder.getService()

mBound = true

}

override fun onServiceDisconnected(arg0: ComponentName) {

mBound = false

}

}

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.main)

}

override fun onStart() {

super.onStart()

// Bind to LocalService

Intent(this, LocalService::class.java).also { intent ->

bindService(intent, connection, Context.BIND_AUTO_CREATE)

}

}

override fun onStop() {

super.onStop()

unbindService(connection)

mBound = false

}

/** Called when a button is clicked (the button in the layout file attaches to

* this method with the android:onClick attribute) */

fun onButtonClick(v: View) {

if (mBound) {

// Call a method from the LocalService.

// However, if this call were something that might hang, then this request should

// occur in a separate thread to avoid slowing down the activity performance.

val num: Int = mService.randomNumber

Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show()

}

}

}Java

public class BindingActivity extends Activity {

LocalService mService;

boolean mBound = false;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}

@Override

protected void onStart() {

super.onStart();

// Bind to LocalService

Intent intent = new Intent(this, LocalService.class);

bindService(intent, connection, Context.BIND_AUTO_CREATE);

}

@Override

protected void onStop() {

super.onStop();

unbindService(connection);

mBound = false;

}

/** Called when a button is clicked (the button in the layout file attaches to

* this method with the android:onClick attribute) */

public void onButtonClick(View v) {

if (mBound) {

// Call a method from the LocalService.

// However, if this call were something that might hang, then this request should

// occur in a separate thread to avoid slowing down the activity performance.

int num = mService.getRandomNumber();

Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();

}

}

/** Defines callbacks for service binding, passed to bindService() */

private ServiceConnection connection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName className,

IBinder service) {

// We've bound to LocalService, cast the IBinder and get LocalService instance

LocalBinder binder = (LocalBinder) service;

mService = binder.getService();

mBound = true;

}

@Override

public void onServiceDisconnected(ComponentName arg0) {

mBound = false;

}

};

}

上例说明了客户端如何使用

注意:在上例中,其他说明中所述,客户端应在适当时机与服务取消绑定。

使用 Messenger

如果您需要让服务与远程进程通信,则可使用

为接口使用

对于大多数应用,服务无需执行多线程处理,因此使用 AIDL 来定义接口。

以下是对

服务实现一个

客户端使用

这样,客户端便没有调用服务的方法。相反,客户端会传递服务在其

下面这个简单的服务实例展示了如何使用

Kotlin

/** Command to the service to display a message */

private const val MSG_SAY_HELLO = 1

class MessengerService : Service() {

/**

* Target we publish for clients to send messages to IncomingHandler.

*/

private lateinit var mMessenger: Messenger

/**

* Handler of incoming messages from clients.

*/

internal class IncomingHandler(

context: Context,

private val applicationContext: Context = context.applicationContext

) : Handler() {

override fun handleMessage(msg: Message) {

when (msg.what) {

MSG_SAY_HELLO ->

Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show()

else -> super.handleMessage(msg)

}

}

}

/**

* When binding to the service, we return an interface to our messenger

* for sending messages to the service.

*/

override fun onBind(intent: Intent): IBinder? {

Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show()

mMessenger = Messenger(IncomingHandler(this))

return mMessenger.binder

}

}Java

public class MessengerService extends Service {

/**

* Command to the service to display a message

*/

static final int MSG_SAY_HELLO = 1;

/**

* Handler of incoming messages from clients.

*/

static class IncomingHandler extends Handler {

private Context applicationContext;

IncomingHandler(Context context) {

applicationContext = context.getApplicationContext();

}

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case MSG_SAY_HELLO:

Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show();

break;

default:

super.handleMessage(msg);

}

}

}

/**

* Target we publish for clients to send messages to IncomingHandler.

*/

Messenger mMessenger;

/**

* When binding to the service, we return an interface to our messenger

* for sending messages to the service.

*/

@Override

public IBinder onBind(Intent intent) {

Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();

mMessenger = new Messenger(new IncomingHandler(this));

return mMessenger.getBinder();

}

}

客户端只需根据服务返回的 MSG_SAY_HELLO 消息的简单 Activity:

Kotlin

class ActivityMessenger : Activity() {

/** Messenger for communicating with the service. */

private var mService: Messenger? = null

/** Flag indicating whether we have called bind on the service. */

private var bound: Boolean = false

/**

* Class for interacting with the main interface of the service.

*/

private val mConnection = object : ServiceConnection {

override fun onServiceConnected(className: ComponentName, service: IBinder) {

// This is called when the connection with the service has been

// established, giving us the object we can use to

// interact with the service. We are communicating with the

// service using a Messenger, so here we get a client-side

// representation of that from the raw IBinder object.

mService = Messenger(service)

bound = true

}

override fun onServiceDisconnected(className: ComponentName) {

// This is called when the connection with the service has been

// unexpectedly disconnected -- that is, its process crashed.

mService = null

bound = false

}

}

fun sayHello(v: View) {

if (!bound) return

// Create and send a message to the service, using a supported 'what' value

val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0)

try {

mService?.send(msg)

} catch (e: RemoteException) {

e.printStackTrace()

}

}

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.main)

}

override fun onStart() {

super.onStart()

// Bind to the service

Intent(this, MessengerService::class.java).also { intent ->

bindService(intent, mConnection, Context.BIND_AUTO_CREATE)

}

}

override fun onStop() {

super.onStop()

// Unbind from the service

if (bound) {

unbindService(mConnection)

bound = false

}

}

}Java

public class ActivityMessenger extends Activity {

/** Messenger for communicating with the service. */

Messenger mService = null;

/** Flag indicating whether we have called bind on the service. */

boolean bound;

/**

* Class for interacting with the main interface of the service.

*/

private ServiceConnection mConnection = new ServiceConnection() {

public void onServiceConnected(ComponentName className, IBinder service) {

// This is called when the connection with the service has been

// established, giving us the object we can use to

// interact with the service. We are communicating with the

// service using a Messenger, so here we get a client-side

// representation of that from the raw IBinder object.

mService = new Messenger(service);

bound = true;

}

public void onServiceDisconnected(ComponentName className) {

// This is called when the connection with the service has been

// unexpectedly disconnected -- that is, its process crashed.

mService = null;

bound = false;

}

};

public void sayHello(View v) {

if (!bound) return;

// Create and send a message to the service, using a supported 'what' value

Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);

try {

mService.send(msg);

} catch (RemoteException e) {

e.printStackTrace();

}

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}

@Override

protected void onStart() {

super.onStart();

// Bind to the service

bindService(new Intent(this, MessengerService.class), mConnection,

Context.BIND_AUTO_CREATE);

}

@Override

protected void onStop() {

super.onStop();

// Unbind from the service

if (bound) {

unbindService(mConnection);

bound = false;

}

}

}

请注意,此示例并未展示服务如何对客户端做出响应。如果您想让服务做出响应,还需在客户端中创建一个

绑定到服务

应用组件(客户端)可通过调用

注意:只有 Activity、服务和内容提供程序可以绑定到服务,您无法从广播接收器绑定到服务。

如要从您的客户端绑定到服务,请按以下步骤操作:

实现

您的实现必须替换两个回调方法:

系统会调用该方法以传递服务的

当与服务的连接意外中断时,例如服务崩溃或被终止时,Android 系统会调用该方法。当客户端取消绑定时,系统不会调用该方法。

调用

注意:如果该方法返回 false,说明您的客户端与服务之间并无有效连接。不过,您的客户端仍应调用

当系统调用

如要断开与服务的连接,请调用

当应用销毁客户端时,如果客户端仍与服务保持绑定状态,销毁会导致客户端取消绑定。更好的做法是在客户端与服务交互完成后,就立即取消客户端的绑定。这样做可以关闭空闲的服务。如需详细了解有关绑定和取消绑定的适当时机,请参阅其他说明。

以下示例通过扩展 Binder 类将客户端连接到上面创建的服务,因此它只需将返回的 LocalBinder 类并请求 LocalService 实例:

Kotlin

var mService: LocalService

val mConnection = object : ServiceConnection {

// Called when the connection with the service is established

override fun onServiceConnected(className: ComponentName, service: IBinder) {

// Because we have bound to an explicit

// service that is running in our own process, we can

// cast its IBinder to a concrete class and directly access it.

val binder = service as LocalService.LocalBinder

mService = binder.getService()

mBound = true

}

// Called when the connection with the service disconnects unexpectedly

override fun onServiceDisconnected(className: ComponentName) {

Log.e(TAG, "onServiceDisconnected")

mBound = false

}

}Java

LocalService mService;

private ServiceConnection mConnection = new ServiceConnection() {

// Called when the connection with the service is established

public void onServiceConnected(ComponentName className, IBinder service) {

// Because we have bound to an explicit

// service that is running in our own process, we can

// cast its IBinder to a concrete class and directly access it.

LocalBinder binder = (LocalBinder) service;

mService = binder.getService();

mBound = true;

}

// Called when the connection with the service disconnects unexpectedly

public void onServiceDisconnected(ComponentName className) {

Log.e(TAG, "onServiceDisconnected");

mBound = false;

}

};

Kotlin

Intent(this, LocalService::class.java).also { intent ->

bindService(intent, connection, Context.BIND_AUTO_CREATE)

}Java

Intent intent = new Intent(this, LocalService.class);

bindService(intent, connection, Context.BIND_AUTO_CREATE);

注意:如果您使用 intent 绑定到 显式 intent 来确保应用的安全性。使用隐式 intent 启动服务存在安全隐患,因为您无法确定哪些服务将响应 intent,且用户无法看到哪些服务已启动。从 Android 5.0(API 级别 21)开始,如果使用隐式 intent 调用

第三个参数是指示绑定选项的标记。如要创建尚未处于活动状态的服务,此参数通常应为 0(表示无此参数)。

其他说明

以下是一些有关绑定到服务的重要说明:

您应该始终捕获

对象是跨进程计数的引用。

如以下示例所述,在匹配客户端生命周期的引入 (bring-up) 和退出 (tear-down) 时刻期间,您通常需配对绑定和取消绑定:

如果您只需在 Activity 可见时与服务交互,应在

如果您希望 Activity 即使在后台停止运行状态下仍可接收响应,那么您可以在

注意:通常情况下,不应在 Activity 的 此外,如果您的应用内的多个 Activity 绑定到同一服务,并且其中两个 Activity 之间发生了转换,那么如果当前 Activity 先取消绑定(暂停期间),然后下一个 Activity 再进行绑定(恢复期间),系统可能就会销毁后再重新创建该服务。如需了解 Activity 如何协调其生命周期的 Activity 转换,请参阅 Activity 文档。

如需查看更多展示如何绑定到服务的示例代码,请参阅 ApiDemos 中的 RemoteService.java 类。

管理绑定服务的生命周期

当服务与所有客户端之间的绑定全部取消时,Android 系统会销毁该服务(除非还使用

不过,如果您选择实现 在此情况下,服务将一直运行,直到其通过

此外,如果您的服务已启动并接受绑定,那么当系统调用您的 true。

a582b2795021083a3be8c15fd1c98ceb.png

图 1. 已启动并且还允许绑定的服务的生命周期。

如需详细了解已启动服务的生命周期,请参阅服务文档。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值