android之Service(3)Bound Service

Bound Service是Android中一种服务实现,允许组件进行绑定、交互和进程间通信。客户端通过bindService()绑定服务,系统调用onBind()返回IBinder。服务通过Binder、Messenger或AIDL提供接口。当所有客户端解绑后,服务会被销毁。Bound Service适用于为其他组件提供服务的场景,而Started Service则持续后台运行。解绑时需注意Service状态,防止意外崩溃。
摘要由CSDN通过智能技术生成

简介

Bound Service是客户端-服务器模式的Service。Bound Service允许组件(Activity,Service,Content Provider,广播不能绑定服务)对其进行绑定、发送请求、接收响应、甚至进行进程间通信(interprocess communication IPC)。 Bound Service一般只在为其它应用程序组件服务期间才是存活的,而不会一直在后台保持运行。

Bound Service是 Service 类的一种实现,它允许其它应用程序与其绑定并交互。为了让服务支持绑定,你必须实现 onBind(Intent)回调方法。这个方法返回一个 IBinder 对象,该对象定义了客户端与服务进行交互时所需的编程接口。客户端可以通过调用bindService()方法来绑定服务。

Bound Service绑定过程

应用程序组件(客户端)可以通过调用 bindService()方法来绑定服务,系统会调用服务的 onBind(Intent)回调方法,返回一个用于和服务进行交互的 IBinder 对象。绑定是异步进行的。 bindService() 将立即返回,并不会立即向客户端返回 IBinder 。为了接收 IBinder对象,客户端必须创建一个ServiceConnection 的实例,并把它传给 bindService() 。ServiceConnection 包含了一个回调方法,系统将会调用该方法来传递客户端所需的那个 IBinder 。

  • 只有activity、服务和content provider才可以绑定到服务上——广播接收器(broadcast receiver)不能绑定服务。

Bound Service绑定过程如下:

  1. 自定义一个Service继承Service类(当然需要在AndroidManifest.xml中注册),并重写onBind(Intent)方法,此方法中需要返回IBinder对象。
  2. 在组件中自定义一个ServiceConnection(ServiceConnection是一个接口)接口对象实现onServiceConnected(ComponentName, IBinder)方法(调用该方法来处理服务的onBind()方法返回的 IBinder 对象)和onServiceDisconnected方法(当与服务的绑定发生意外中断时,比如服务崩溃或者被杀死时,系统将会调用该方法,客户端解除绑定时,不会调用该方法)。
  3. 通过bindService (Intent, ServiceConnection, int)方法将Service绑定到组件上。int值为选择绑定的方式,系统提供。
  4. 通过获取的IBinder对象实现进程间通信(IPC)。
  5. 当客户端在恰当的生命周期时,此时需要解绑之前已经绑定的Service,通过调用unbindService(ServiceConnection)方法。当客户端被销毁时,与服务的绑定也将解除。但与服务交互完毕后,或者你的activity进入pause状态时,你都应该确保解除绑定,以便服务能够在用完后及时关闭。
  6. 多个客户端可以同时绑定到一个服务上。不过,只有在第一个客户端绑定时,系统才会调用服务的 onBind()方法来获取 IBinder 对象。然后,系统会向后续请求绑定的客户端传送这同一个 IBinder对象,而不再调用onBind()方法。当最后一个客户端解除绑定后,系统会销毁服务(除非服务先通过 startService()启动的,且绑定时不再调用onCreate()方法)。

下面具体分解以上步骤

自定义一个Service类

在自定义Service类中根据onBind(Intent)方法返回的对象,分为三种通信方式:

  1. Extending the Binder class
    继承Binder类。如果服务是应用程序私有的,并且与客户端运行于同一个进程中(通常都是如此,也就是本地通信),那么直接通过扩展 Binder 类(继承了IBinder类)来创建一个IBinder实例,并从 onBind()返回一个它的实例。客户端通过该 Binder 对象获取Service实例并处理业务功能。如果服务只是为该应用程序执行一些后台工作,那这就是首选的技术方案。若服务要被其它应用程序使用或者要跨多个进程使用,则这种方式不行。
  2. Using a Messenger
    使用Messenger。
    Messenger
  3. Using AIDL
    使用AIDL。Android接口定义语言AIDL(Android Interface Definition Language) 可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。完成以下的所有工作:将对象解析为操作系统可识别的原始形态,并将它们跨进程序列化(marshal)以完成IPC。 前一个使用 Messenger 的方式,实际上也是基于AIDL的,它用AIDL作为底层结构。如上所述, Messenger 将在一个单独的进程中创建一个包含了所有客户端请求的队列,这样服务每次就只会收到一个请求(即不支持并发处理)。 可是,如果想让你的服务能同时处理多个请求,那你就可以直接使用AIDL。 这种情况下,你的服务必须拥有多线程处理能力,并且是以线程安全的方式编写的。要直接使用AIDL,你必须创建一个.aidl文件,其中定义了编程的接口。 Android SDK 工具使用此文件来生成一个抽象类(abstract class),其中实现了接口及对IPC的处理,然后你就可以在自己的服务中扩展该类。注意: 绝大多数应用程序都不应该用AIDL来创建Bound Service,因为这可能需要多线程处理能力并且会让代码变得更为复杂。 因此,AIDL对绝大多数应用程序都不适用。是否如此???

扩展Binder类

根据官方文档中的示例代码修改代码如下:

package com.sywyg.servicetest;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

import java.util.Random;

public class LocalService extends Service {
   
    // Binder given to clients
    private final IBinder mBinder = 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.
     * 在同一进程中通信,并非IPC
     */
    public class LocalBinder extends Binder {
   
        /**
         * 通过该方法获取LocalService对象
         */
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            Log.d("result","getService executed");
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d("result","onBind...");
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("result","onUnbind...");
        return super.onUnbind(intent);
    }

    /**
     * method for clients
     * 模拟客户端需要处理的方法
     */
    public int getRandomNumber() {
        return mGenerator.nextInt(100);
    }
}

对应activity中的代码如下:

package com.sywyg.servicetest;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Toast;


public class BindingActivity extends Activity {
   
    LocalService mService;
    boolean mBound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_binding);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService
        //绑定服务
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        //解除绑定
        if
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值