android之Service(3)Bound Service

  • 简介
  • Bound Service绑定过程
    • 自定义一个Service类
      • 扩展Binder类
      • Using a Messenger
      • Using AIDL
        • 传输自定义类型
        • 与Messenger比较
        • AIDL使用总结
  • Started Service 和Bound Service区别
    • 解绑和销毁服务

简介

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。
  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 (mBound) {
            unbindService(mConnection);
            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() * 若onBind(Intent intent)方法不返回对象则不调用该ServiceConnection实例 */
    private ServiceConnection mConnection = new ServiceConnection() {
//执行该方法表示绑定成功,并可以调用服务了。
        @Override
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
            mService = binder.getService();
            Log.d("result", "onServiceConnected...");
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            Log.d("result", "onServiceDisconnected...");
            mBound = false;
        }
    };
}

就不演示结果了。
官方文档中给出的示例果然不错以后要多考虑文档上的例子。

可以看到通过上面这种方式可以实现同一进程间客户端(Client)和Bound Service之间的通信。局限:客户端与Service必须属于同一个进程,不能实现进程间通信(IPC)。否则会出现类似于“android.os.BinderProxy cannot be cast to xxx”错误。
注:在四大基本组件中,BroadcastReceiver不能作为Bound Service的客户端,因为BroadcastReceiver的生命周期很短,当执行完onReceive()回调时,BroadcastReceiver生命周期完结。而Bound Service又与Client本身的生命周期相关,因此,Android中不允许BroadcastReceiver去bindService(),当有此类需求时,可以考虑通过startService()(四大组件Started Service 都是通过startService())。

Using a Messenger

如果需要远程通信,可以使用一个 Messenger 来提供服务的接口。这种技术能无需使用AIDL就能进行进程间通信(IPC)。
Messenger具体使用步骤如下:

  1. Service中实现一个 Handler对象,用于客户端每次调用时处理消息。
  2. 通过Handler对象创建一个Messenger对象,并通过该对象的getBinder()方法在onBind()中返回Binder对象。
  3. 在调用的组件中,通过ServiceConnection接口对象的onServiceConncet()方法,中传递过来的IBinder对象创建一个Messenger对象。这样两个Messenger对象关联到同一个IBinder对象上,从而实现IPC。
  4. 在调用组件中通过Messenger中的send()方法将消息发送到Service的Messenger对象中。

具体代码如下。
自定义服务MyMessengerService如下:

package com.sywyg.servicetest;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.widget.Toast;

public class MyMessengerService extends Service {
    public static final int SAY_HELLO = 1;
    public MyMessengerService() {
    }
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message message) {
            switch (message.what) {
                case SAY_HELLO:                  Toast.makeText(MyMessengerService.this,"MyMessengerService",Toast.LENGTH_LONG).show();
                    break;
            }
        }
    };
    private Messenger messenger = new Messenger(handler);
    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
}

对应的Activity代码如下:

package com.sywyg.servicetest;

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.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;


public class MessengerActivity extends ActionBarActivity {
    private Messenger messenger;
    private boolean mbound = false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.messenger_main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(MessengerActivity.this,MyMessengerService.class);
        bindService(intent,mconn, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(mbound){
            unbindService(mconn);
            mbound = false;
        }
    }

    public void onButtonClick(View view){
        Message message = Message.obtain();
        message.what = MyMessengerService.SAY_HELLO;
        try {
            messenger.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
    private ServiceConnection mconn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d("result","onServiceConnected executed");
            messenger = new Messenger(service);
            mbound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mbound = false;
        }
    };
}

Using AIDL

AIDL(Android Interface Definition Language)是Android接口定义语言的意思,可以用于多个应用程序组件与Bound Service之间进行进程间通信,从而可以实现多个应用程序共享同一个Service的功能。

具体使用步骤如下:
首先需要新建一个AIDL文件,在这个文件中定义好组件(如Activity)需要与Service进行通信的业务对象。新建IPerson.aidl文件,代码如下所示:

// IPerson.aidl
//包名是必须的
package com.sywyg.servicetest;

/** *aidl文件内不能使用修饰符 *支持的数据类型:基本数据类型,String,CharSequence,List,Map,自定义 */

interface IPerson {

    void setName(String name);
    void setAge(int age);
    String getPerson();
}

如果你使用eclipse的话会在gen目录下自动生成一个对应的java文件;若你使用的是android studio,则请看1。

打开对应的IPerson.java代码如下:

/* * This file is auto-generated. DO NOT MODIFY. * Original file: D:\\AndroidStudioProjects\\ServiceTest\\app\\src\\main\\aidl\\com\\sywyg\\servicetest\\IPerson.aidl */
package com.sywyg.servicetest;
/** *aidl内不能使用修饰符 *支持的数据类型:基本数据类型,String,CharSequence,List,Map,自定义 */
public interface IPerson extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.sywyg.servicetest.IPerson {
        private static final java.lang.String DESCRIPTOR = "com.sywyg.servicetest.IPerson";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /** * Cast an IBinder object into an com.sywyg.servicetest.IPerson interface, * generating a proxy if needed. */
        public static com.sywyg.servicetest.IPerson asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.sywyg.servicetest.IPerson))) {
                return ((com.sywyg.servicetest.IPerson)iin);
            }
            return new com.sywyg.servicetest.IPerson.Stub.Proxy(obj);
        }
        @Override public android.os.IBinder asBinder()
        {
            return this;
        }
        @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
        {
            switch (code)
            {
                case INTERFACE_TRANSACTION:
                {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_setName:
                {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.setName(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_setAge:
                {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    this.setAge(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getPerson:
                {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _result = this.getPerson();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
        private static class Proxy implements com.sywyg.servicetest.IPerson {
            private android.os.IBinder mRemote;
            Proxy(android.os.IBinder remote)
            {
                mRemote = remote;
            }
            @Override public android.os.IBinder asBinder()
            {
                return mRemote;
            }
            public java.lang.String getInterfaceDescriptor()
            {
                return DESCRIPTOR;
            }
            @Override public void setName(java.lang.String name) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(name);
                    mRemote.transact(Stub.TRANSACTION_setName, _data, _reply, 0);
                    _reply.readException();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
            @Override public void setAge(int age) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(age);
                    mRemote.transact(Stub.TRANSACTION_setAge, _data, _reply, 0);
                    _reply.readException();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
            @Override public java.lang.String getPerson() throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPerson, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
        static final int TRANSACTION_setName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_setAge = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_getPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    }
    public void setName(java.lang.String name) throws android.os.RemoteException;
    public void setAge(int age) throws android.os.RemoteException;
    public java.lang.String getPerson() throws android.os.RemoteException;
}

这是一个自动生成的java文件,提示不能修改。其中,该接口中有一个内部抽象类Stub,public static abstract class Stub extends android.os.Binder implements com.sywyg.servicetest.IPerson。可以看到Stub类继承了Binder并实现aidl接口。Stub英文表示存根的意思,该类在服务端进程,我们必须继承该类并实现aidl接口中的方法。具体代码如下:

package com.sywyg.servicetest;

import android.os.RemoteException;

/** * 实现自己的业务功能 * Created by sywyg on 2015/5/4. */
public class PersonImpl extends IPerson.Stub{
    private String name;
    private int age;
    @Override
    public void setName(String name) throws RemoteException {
        this.name = name;
    }
    @Override
    public void setAge(int age) throws RemoteException {
        this.age = age;
    }

    @Override
    public String getPerson() throws RemoteException {
        return "name:" + name + ",age:" + age;
    }
}

服务端代码如下:

package com.sywyg.servicetest;

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

/** * 实现一个绑定服务类,这里实现本地通信 * 这里是B应用,和aidl属于一个业务,因此可以直接使用自定义的业务对象 * * @author sywyg * @since 2015/5/4 */
public class MyBindService extends Service {
    private PersonImpl person;
    public MyBindService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d("result","onBind...");
        person = new PersonImpl();
       return person;
    }

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

对应的Activity代码如下:


package com.sywyg.servicetest;

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.os.RemoteException;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;


public class MainActivity2 extends ActionBarActivity implements View.OnClickListener{
    private Button btn_bind;
    private Button btn_unbind;
    private Button btn_call_person;
    private IPerson person;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        btn_bind = (Button)findViewById(R.id.btn_bind);
        btn_unbind = (Button)findViewById(R.id.btn_unbind);
        btn_call_person = (Button)findViewById(R.id.btn_call_person);
        btn_bind.setOnClickListener(this);
        btn_unbind.setOnClickListener(this);
        btn_call_person.setOnClickListener(this);
    }

    //服务连接对象
    private ServiceConnection conn = new ServiceConnection() {
        /** * * 绑定成功后会调用该方法 * @param name * @param service */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d("result","onServiceConnected...");
            //判断本地调用还是远程调用关键代码
            person = IPerson.Stub.asInterface(service);

        }

        /** * 当服务异常终止后调用,解除绑定时不会调用 * @param name */
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d("result","onServiceDisconnected...");
        }
    };
    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.btn_bind:
                Intent intent = new Intent(this,MyBindService.class);
                /** * 参数分别为:Intent对象,服务连接对象,绑定服务的标记(Context.BIND_AUTO_CREATE若服务没启动则先启动), * 后续详解 */
                bindService(intent,conn,Context.BIND_AUTO_CREATE);
                break;
            case R.id.btn_unbind:
                unbindService(conn);
                break;
            case R.id.btn_call_person:
                //调用远程对象或本地对象
                try {
                    person.setName("sywyg");
                    person.setAge(26);
                    Toast.makeText(this,person.getPerson(),Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }
    }
}

其中,关键代码是:onServiceConnect()方法中的person = IPerson.Stub.asInterface(service)。而asInterface()方法在自动生成的IPerson.java中的源码如下:


public static com.sywyg.servicetest.IPerson asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.sywyg.servicetest.IPerson))) {
                return ((com.sywyg.servicetest.IPerson)iin);
            }
            return new com.sywyg.servicetest.IPerson.Stub.Proxy(obj);
        }

该方法无论如何都会返回一个IPerson对象,该方法实现了远程通信和本地通信。
以上是使用AIDL实现本地通信。对于远程通信,你可以再新建一个应用程序或者在AndroidMainfest.xml<service>标签中添加属性android:process=":remote"则Service就会运行在以包名加remote命名的进程中(而应用组件则是运行在包名命名的进程中),PersonImpl 类和Service在同一个进程中。当android:process=”:remote”使用“:”分号时,代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process=”remote”,没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。

传输自定义类型

若要在aidl接口中使用自定义类型,
首先该自定义类应实现Parcelable接口,其次新建一个和自定义类同名的aidl文件对自定义类进行声明,文件内容如下填写:

//包名也是必须的,否则出错
package com.sywyg.servicetest;
//Man为自定义类的类名
parcelable Man;

最后需在使用该自定义类的aidl文件中导入该类import com.sywyg.servicetest.Man;

与Messenger比较

当需要进行IPC时,使用 Messenger 要比用AIDL实现接口要容易些,因为 Messenger 会把所有调用服务的请求放入一个队列。而纯粹的AIDL接口会把这些请求同时发送给服务,这样服务就必须要能够多线程运行。
对于绝大多数应用程序而言,服务没有必要多线程运行,因此利用 Messenger 可以让服务一次只处理一个调用。如果 你的服务非要多线程运行,那你就应该用 AIDL 来定义接口。

AIDL使用总结

使用aidl来定义接口,通过ADT工具生成一个对应的Java类,此类实现了进程间远程通讯的代理;编写自己的业务类(继承自动生成的类中的Stub抽象类)实现业务接口功能;再通过绑定Service的方式暴露此业务对象,给其它组件提供功能,以此实现进程间通信。

调用者可以通过bindService()方法绑定服务,从而可以获得绑定成功的远程业务对象或本地业务对象,可以调用相关功能。

Started Service 和Bound Service区别

  1. 通过Started Service方式的服务一直运行在后台,需要服务本身或外部组件来停止服务才会销毁(IntentService除外)。Bound Service的生命周期是依附于绑定该服务的client的生命周期的,当client不存在时,Bound Service将执行onDestroy()方法自动销毁。(注意解除绑定并未销毁该Service,前提是绑定的Service没提前启动)
  2. Started Service可以让组件给启动的服务传递参数(Intent),但无法获取服务中方法的返回值;Bound Service不仅可以让组件给服务传递参数(Intent),也可以让组件获取绑定的业务对象获取返回结果。
    一般情况下,第一次先使用Started启动一个服务,之后通过Bound Service绑定服务,从而直接调用业务功能获取返回值。
    根据验证得出的结论是:
    若绑定服务则调用stopService()方法一样可以解绑并销毁Service,同样在启动之后再绑定也是一样。

解绑和销毁服务

  1. 无论哪种方式的Bound Service,在进行unbind(ServiceConnection)时,都需要注意当前Service是否处于已经绑定状态,否则可能会因为当前Service已经解绑后继续执行unbind(ServiceConnection)会导致崩溃。因此通常设置一个boolean型标记判断是否已经绑定或解绑
    这点与Started Service区别很大(如前文所述:stopService()无需做当前Service是否有效的判断)。
  2. 多个客户端可以同时绑定到一个服务上。不过,只有在第一个客户端绑定时,系统才会调用服务的 onBind()方法来获取 IBinder 对象。然后,系统会向后续请求绑定的客户端传送这同一个 IBinder对象,而不再调用onBind()方法。当最后一个客户端解除绑定后,系统会销毁服务(除非服务先通过 startService()启动的,且绑定时不再调用onCreate()方法)。

http://blog.csdn.net/huangbiao86/article/details/7035920
http://www.cnblogs.com/lwbqqyumidi/p/4181185.html
http://blog.csdn.net/guolin_blog/article/details/11952435
http://blog.sina.com.cn/s/blog_48d4913001010696.html
威哥视频
第一行代码

  1. http://www.linuxidc.com/Linux/2015-01/111148.htm ↩

你可能感兴趣的:(android,service)