简介
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绑定过程如下:
- 自定义一个Service继承Service类(当然需要在AndroidManifest.xml中注册),并重写
onBind(Intent)方法,此方法中需要返回IBinder对象。 - 在组件中自定义一个ServiceConnection(ServiceConnection是一个接口)接口对象实现
onServiceConnected(ComponentName, IBinder)方法(调用该方法来处理服务的onBind()方法返回的 IBinder 对象)和onServiceDisconnected方法(当与服务的绑定发生意外中断时,比如服务崩溃或者被杀死时,系统将会调用该方法,客户端解除绑定时,不会调用该方法)。 - 通过bindService (Intent, ServiceConnection, int)方法将Service绑定到组件上。int值为选择绑定的方式,系统提供。
- 通过获取的IBinder对象实现进程间通信(IPC)。
- 当客户端在恰当的生命周期时,此时需要解绑之前已经绑定的Service,通过调用
unbindService(ServiceConnection)方法。当客户端被销毁时,与服务的绑定也将解除。但与服务交互完毕后,或者你的activity进入pause状态时,你都应该确保解除绑定,以便服务能够在用完后及时关闭。 - 多个客户端可以同时绑定到一个服务上。不过,只有在第一个客户端绑定时,系统才会调用服务的
onBind()方法来获取 IBinder 对象。然后,系统会向后续请求绑定的客户端传送这同一个 IBinder对象,而不再调用onBind()方法。当最后一个客户端解除绑定后,系统会销毁服务(除非服务先通过startService()启动的,且绑定时不再调用onCreate()方法)。
下面具体分解以上步骤
自定义一个Service类
在自定义Service类中根据onBind(Intent)方法返回的对象,分为三种通信方式:
- Extending the Binder class
继承Binder类。如果服务是应用程序私有的,并且与客户端运行于同一个进程中(通常都是如此,也就是本地通信),那么直接通过扩展 Binder 类(继承了IBinder类)来创建一个IBinder实例,并从onBind()返回一个它的实例。客户端通过该 Binder 对象获取Service实例并处理业务功能。如果服务只是为该应用程序执行一些后台工作,那这就是首选的技术方案。若服务要被其它应用程序使用或者要跨多个进程使用,则这种方式不行。 - Using a Messenger
使用Messenger。
- 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具体使用步骤如下:
- Service中实现一个 Handler对象,用于客户端每次调用时处理消息。
- 通过Handler对象创建一个Messenger对象,并通过该对象的
getBinder()方法在onBind()中返回Binder对象。 - 在调用的组件中,通过ServiceConnection接口对象的
onServiceConncet()方法,中传递过来的IBinder对象创建一个Messenger对象。这样两个Messenger对象关联到同一个IBinder对象上,从而实现IPC。 - 在调用组件中通过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区别
- 通过Started Service方式的服务一直运行在后台,需要服务本身或外部组件来停止服务才会销毁(IntentService除外)。Bound Service的生命周期是依附于绑定该服务的client的生命周期的,当client不存在时,Bound Service将执行
onDestroy()方法自动销毁。(注意解除绑定并未销毁该Service,前提是绑定的Service没提前启动) - Started Service可以让组件给启动的服务传递参数(Intent),但无法获取服务中方法的返回值;Bound Service不仅可以让组件给服务传递参数(Intent),也可以让组件获取绑定的业务对象获取返回结果。
一般情况下,第一次先使用Started启动一个服务,之后通过Bound Service绑定服务,从而直接调用业务功能获取返回值。
根据验证得出的结论是:
若绑定服务则调用stopService()方法一样可以解绑并销毁Service,同样在启动之后再绑定也是一样。
解绑和销毁服务
- 无论哪种方式的Bound Service,在进行
unbind(ServiceConnection)时,都需要注意当前Service是否处于已经绑定状态,否则可能会因为当前Service已经解绑后继续执行unbind(ServiceConnection)会导致崩溃。因此通常设置一个boolean型标记判断是否已经绑定或解绑
这点与Started Service区别很大(如前文所述:stopService()无需做当前Service是否有效的判断)。 - 多个客户端可以同时绑定到一个服务上。不过,只有在第一个客户端绑定时,系统才会调用服务的
onBind()方法来获取 IBinder 对象。然后,系统会向后续请求绑定的客户端传送这同一个 IBinder对象,而不再调用onBind()方法。当最后一个客户端解除绑定后,系统会销毁服务(除非服务先通过startService()启动的,且绑定时不再调用onCreate()方法)。
http://blog.youkuaiyun.com/huangbiao86/article/details/7035920
http://www.cnblogs.com/lwbqqyumidi/p/4181185.html
http://blog.youkuaiyun.com/guolin_blog/article/details/11952435
http://blog.sina.com.cn/s/blog_48d4913001010696.html
威哥视频
第一行代码
Bound Service是Android中一种服务实现,允许组件进行绑定、交互和进程间通信。客户端通过bindService()绑定服务,系统调用onBind()返回IBinder。服务通过Binder、Messenger或AIDL提供接口。当所有客户端解绑后,服务会被销毁。Bound Service适用于为其他组件提供服务的场景,而Started Service则持续后台运行。解绑时需注意Service状态,防止意外崩溃。
602

被折叠的 条评论
为什么被折叠?



