您的位置:首页 > 移动开发 > Android开发

Android四大组件之Service

2015-08-30 16:58 567 查看

一、Service简介

Service作为安卓四大组件之一,用来执行长期运行的后台操作,并且不提供用户界面。其他组件可以启动Service,即使是用户切换到其他应用(Application)了,Service也会继续运行在后台。不仅如此,服务还可以用来进行进程间通信(IPC)。Service还能进行网络交易,播放音乐,文件操作,与另一个组件内容提供者(Content Provider)进行交互等,这些操作都是在后台进行的。

二、Service的两种基本形式

1.Service可以使用两种基本形式。

(i)Started

一个组件(如Activity)可以使用startService()方法来启动服务。这种方式启动的服务会在后台一直运行,即使用来启动他的组件已经被销毁。

通常,这种服务只执行一种操作,并且不返回结果给启动它的组件。比如,它可以通过网络来上传或下载文件。当这个操作完成时,服务应当关闭自己重点内容。

(ii)Bound

一个组件(如Activity)可以使用bindService()方法绑定服务。一个绑定的Service提供一个客户端-服务端接口来与其他组件进行交互、发送请求、获取结果,甚至通过进程间通信(IPC)来进行上述操作。

只要绑定这个Service的组件开始运行,这个Service就会开始运行,一旦这个组件解除绑定,这个Service就会被系统销毁。多个组件可以同时绑定同一个Service,但是当他们全部解除绑定,服务就会被销毁。

说明:虽然Service有这两个形式,但是一个Service可以同时以两种形式运行。Started Service也允许被绑定。不管一个Service是Started、Bound或者两者,默认情况下任何其他应用组件都能使用这个Service(即使是来自不同应用)。不过,我们可以在manifest.xml文件中将服务声明为私有的,从而阻止其他应用使用该Service。

注意:一个服务运行在进程的主线程中,服务不会自己创建子线程,也不会自己运行在不同的进程中(除非我们自己定义)。也就是说,如果你的服务将要进行任何使CPU紧张或阻塞的操作(比如MP3播放或者网络请求),你应该在服务中创建一个子线程来进行这些操作。这样可以降低应用失去响应(ANR)错误的分险,同时,应用的主线程能更专注于与用户交互。

三、Service的生命周期



左边是未绑定的Service的生命周期,右边是绑定的Service 的生命周期。

下图是已经启动同时可绑定的Service的生命周期



1.Service主要以下有5个生命周期方法:

1)onCreate():当Service刚被创建的时候,系统会调用这个方法。并且这个方法只会调用一次。

2)onBind():当其他组件想要使用bindService()这个方法来绑定这个Service的时候,系统会调用这个方法。这个方法需要通过返回一个IBinder对象,提供一个客户端接口用来与Service进行交互。

3)onStartCommand():当其他组件想要使用startService()这个方法来启动这个Service的时候,系统会调用这个方法。一旦这个方法执行了,Service就启动了,并且能在后台无限运行。我们可以在Service所执行的任务完成后掉用stopSelf()或stopService()来停止Service。

4)onUnbind():当其他组件调用unbindService()来解除绑定这个Service时,系统会调用这个方法。

5)onDestroy():如果服务不再被使用并且将要被销毁时,系统会调用这个方法。服务需要重写这个方法来释放资源比如线程,注册的监听或接受者等。

附Service生命周期测试代码:

public
17b93
class ExampleService extends Service {
int mStartMode;       // indicates how to behave if the service is killed
IBinder mBinder;      // interface for clients that bind
boolean mAllowRebind; // indicates whether onRebind should be used

@Override
public void onCreate() {
// The service is being created
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The service is starting, due to a call to startService()
return mStartMode;
}
@Override
public IBinder onBind(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// All clients have unbound with unbindService()
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
// A client is binding to the service with bindService(),
// after onUnbind() has already been called
}
@Override
public void onDestroy() {
// The service is no longer used and is being destroyed
}
}


注意

onStartCommand()方法有三种返回值:

1)START_NOT_STICKY

如果返回这个值,那么当系统杀死这个Service的时候,不会自动重新创建Service,除非使用pending intents。因此,使用这个返回值可以避免在不需要或者应用能轻易重启任何未完成的任务的时候运行Service。

2)START_STICKY

如果返回这个值,那么当系统杀死这个Service的时候,会自动重新创建这个Service并调用onStartCommand()方法。不过,伴随着startCommand()的intent为null,除非使用pending intent来启动Service。这个返回值适用于媒体播放器或类似的Service,即那种不用执行命令,但又无限运行着来等待工作的Service。

3)START_REDELIVER_INTENT

如果返回这个值,那么当系统杀死这个Service的时候,会自动重新创建这个Service,并且intent还是杀死之前最终传递的intent对象。这个返回值适用于那种积极执行任务的Service,比如下载文件。

四、Service的使用方法

1)继承Service

public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;

// 从线程接收消息的Handler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// 通常情况下,我们会在这里执行一个操作,如下载文件
// 本例中至执行sleep5秒操作
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime-System.currentTimeMillis());
} catch (Exception e) {
}
}
}
//使用startId来关闭服务,可以避免关闭正在处理其他任务的服务。
stopSelf(msg.arg1);
}
}

@Override
public void onCreate() {
// Start up the thread running the service.  Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block.  We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();

// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);

// If we get killed, after returning from here, restart
return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}

@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}


2)注册Service

<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>


3)启动Service

(i)使用Service

第一步,继承Service

public class HelloIntentService extends IntentService {

/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}

/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}

That's all you need: a constructor and an implementation of onHandleIntent().

If you decide to also override other callback methods, such as onCreate(), onStartCommand(), or onDestroy(), be sure to call the super implementation, so that the IntentService can properly handle the life of the worker thread.

For example, onStartCommand() must return the default implementation (which is how the intent gets delivered to onHandleIntent()):

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent,flags,startId);
}

Besides onHandleIntent(), the only method from which you don't need to call the super class is onBind() (but you only need to implement that if your service allows binding).

In the next section, you'll see how the same kind of service is implemented when extending the base Service class, which is a lot more code, but which might be appropriate if you need to handle simultaneous start requests.
Extending the Service class

As you saw in the previous section, using IntentService makes your implementation of a started service very simple. If, however, you require your service to perform multi-threading (instead of processing start requests through a work queue), then you can extend the Service class to handle each intent.

For comparison, the following example code is an implementation of the Service class that performs the exact same work as the example above using IntentService. That is, for each start request, it uses a worker thread to perform the job and processes only one request at a time.

public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;

// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}

@Override
public void onCreate() {
// Start up the thread running the service.  Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block.  We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();

// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);

// If we get killed, after returning from here, restart
return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}

@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}


第二步,启动

Intent intent = new Intent(this, HelloService.class);
startService(intent);


(ii)使用IntentService

IntentService默认会执行如下操作:

a)创建一个默认的工作线程来执行所用从Application的主线程被传递到onStartCommand()方法的intents。

b)创建一个工作队列,一次传递一个intent给onHandleIntent()方法,因此不用担心多线程。

c)停止服务当所有start请求都被处理,因此不需要调用stopSelf()方法。

d)提供默认实现onBind()方法,返回null。

f )提供默认实现onStartCommand()方法,来发送intent给工作队列给实现的onHandleIntent()方法。

第一步,创建一个IntentService的子类

public class HelloIntentService extends IntentService {

/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}

/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}


通常情况下,使用IntentService只需要写这两个方法,如果想重写生命周期方法onCreate(),onStartCommand(),onDestroy(),记住使用“super.生命周期方法“,以保证IntentService能适当管理工作线程的生命。例如:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent,flags,startId);
}


如果服务不是绑定的那么onBind()方法可以不使用super。否则,也要super。

第二步,启动

Intent intent = new Intent(this, HelloIntentService .class);
startService(intent);


4)停止Service

(a)服务内部调用stopSelf()方法。

(b)其他组件调用stopService()方法。

5)绑定Service

首先接收客户端如何绑定Service

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;
}
};


Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);


绑定Service似乎不难,但是,要创建一个可绑定的Service,这个Service必须提供一个IBinder对象,用来提供客户端与Service交互的接口。

下面三种方式可以提供这个IBinder对象

(a)继承Binder类

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.
*/
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 mBinder;
}

/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}


绑定服务的Activity,按下按钮,调用服务的getRandomNumber()方法。

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, 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() */
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
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}

@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}


(2)使用Messenger

这个技术允许在不使用AIDL的情况下实现进程间通信。

服务示例:

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.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}

/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());

/**
* 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();
return mMessenger.getBinder();
}
}


绑定服务的Activity,传递”MSG_SAY_HELLO”消息给服务示例:

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 mBound;

/**
* 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);
mBound = 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;
mBound = false;
}
};

public void sayHello(View v) {
if (!mBound) 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 (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}


(3)使用AIDL(安卓接口定义语言)

使用AIDL可以定义编程接口来让客户端与服务使用进程间通信交互。在安卓设备中,一个进程正常情况下不能访问另一个进程的内存。

注意:只有你允许不用应用(Application)访问你的服务进行进程间通信(PIC)并且想要处理多线程的时候才有必要使用AIDL。

如果你不需要PIC通信,那么只需要继承Binder;

如果你需要PIC通信,但是不需要处理多线程,那么只需要使用Messenger。

还有一点需要注意:不同进程间,必须保证AIDL是线程安全的。

(3.1)下面介绍AIDL用法:

(a创建.aidl文件

// IRemoteService.aidl
package com.example.android;

// Declare any non-default types here with import statements

/** Example service interface */
interface IRemoteService {
/** Request the process ID of this service, to do evil things with it. */
int getPid();

/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}


(b)实现该接口

private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public int getPid(){
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
// Does nothing
}
};


(c)公开接口给客户端

public class RemoteService extends Service {
@Override
public void onCreate() {
super.onCreate();
}

@Override
public IBinder onBind(Intent intent) {
// Return the interface
return mBinder;
}

private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { public int getPid(){ return Process.myPid(); } public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) { // Does nothing } };
}


IRemoteService mIRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can use to call on the service
mIRemoteService = IRemoteService.Stub.asInterface(service);
}

// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "Service has unexpectedly disconnected");
mIRemoteService = null;
}
};


(3.2)通过IPC传递对象

这里是Rect.aidl文件

package android.graphics;

// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect;


这里是Rect class如何实现Parcelable协议。

import android.os.Parcel;
import android.os.Parcelable;

public final class Rect implements Parcelable {
public int left;
public int top;
public int right;
public int bottom;

public static final Parcelable.Creator<Rect> CREATOR = new
Parcelable.Creator<Rect>() {
public Rect createFromParcel(Parcel in) {
return new Rect(in);
}

public Rect[] newArray(int size) {
return new Rect[size];
}
};

public Rect() {
}

private Rect(Parcel in) {
readFromParcel(in);
}

public void writeToParcel(Parcel out) {
out.writeInt(left);
out.writeInt(top);
out.writeInt(right);
out.writeInt(bottom);
}

public void readFromParcel(Parcel in) {
left = in.readInt();
top = in.readInt();
right = in.readInt();
bottom = in.readInt();
}
}


(3.3)调用IPC方法

public static class Binding extends Activity {
/** The primary interface we will be calling on the service. */
IRemoteService mService = null;
/** Another interface we use on the service. */
ISecondary mSecondaryService = null;

Button mKillButton;
TextView mCallbackText;

private boolean mIsBound;

/**
* Standard initialization of this activity.  Set up the UI, then wait
* for the user to poke it before doing anything.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.remote_service_binding);

// Watch for button clicks.
Button button = (Button)findViewById(R.id.bind);
button.setOnClickListener(mBindListener);
button = (Button)findViewById(R.id.unbind);
button.setOnClickListener(mUnbindListener);
mKillButton = (Button)findViewById(R.id.kill);
mKillButton.setOnClickListener(mKillListener);
mKillButton.setEnabled(false);

mCallbackText = (TextView)findViewById(R.id.callback);
mCallbackText.setText("Not attached.");
}

/**
* 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 service object we can use to
// interact with the service.  We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
mService = IRemoteService.Stub.asInterface(service);
mKillButton.setEnabled(true);
mCallbackText.setText("Attached.");

// We want to monitor the service for as long as we are
// connected to it.
try {
mService.registerCallback(mCallback);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}

// As part of the sample, tell the user what happened.
Toast.makeText(Binding.this, R.string.remote_service_connected,
Toast.LENGTH_SHORT).show();
}

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;
mKillButton.setEnabled(false);
mCallbackText.setText("Disconnected.");

// As part of the sample, tell the user what happened.
Toast.makeText(Binding.this, R.string.remote_service_disconnected,
Toast.LENGTH_SHORT).show();
}
};

/**
* Class for interacting with the secondary interface of the service.
*/
private ServiceConnection mSecondaryConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// Connecting to a secondary interface is the same as any
// other interface.
mSecondaryService = ISecondary.Stub.asInterface(service);
mKillButton.setEnabled(true);
}

public void onServiceDisconnected(ComponentName className) {
mSecondaryService = null;
mKillButton.setEnabled(false);
}
};

private OnClickListener mBindListener = new OnClickListener() {
public void onClick(View v) {
// Establish a couple connections with the service, binding
// by interface names.  This allows other applications to be
// installed that replace the remote service by implementing
// the same interface.
Intent intent = new Intent(Binding.this, RemoteService.class);
intent.setAction(IRemoteService.class.getName());
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
intent.setAction(ISecondary.class.getName());
bindService(intent, mSecondaryConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
mCallbackText.setText("Binding.");
}
};

private OnClickListener mUnbindListener = new OnClickListener() {
public void onClick(View v) {
if (mIsBound) {
// If we have received the service, and hence registered with
// it, then now is the time to unregister.
if (mService != null) {
try {
mService.unregisterCallback(mCallback);
} catch (RemoteException e) {
// There is nothing special we need to do if the service
// has crashed.
}
}

// Detach our existing connection.
unbindService(mConnection);
unbindService(mSecondaryConnection);
mKillButton.setEnabled(false);
mIsBound = false;
mCallbackText.setText("Unbinding.");
}
}
};

private OnClickListener mKillListener = new OnClickListener() {
public void onClick(View v) {
// To kill the process hosting our service, we need to know its
// PID.  Conveniently our service has a call that will return
// to us that information.
if (mSecondaryService != null) {
try {
int pid = mSecondaryService.getPid();
// Note that, though this API allows us to request to
// kill any process based on its PID, the kernel will
// still impose standard restrictions on which PIDs you
// are actually able to kill.  Typically this means only
// the process running your application and any additional
// processes created by that app as shown here; packages
// sharing a common UID will also be able to kill each
// other's processes.
Process.killProcess(pid);
mCallbackText.setText("Killed service process.");
} catch (RemoteException ex) {
// Recover gracefully from the process hosting the
// server dying.
// Just for purposes of the sample, put up a notification.
Toast.makeText(Binding.this,
R.string.remote_call_failed,
Toast.LENGTH_SHORT).show();
}
}
}
};

// ----------------------------------------------------------------------
// Code showing how to deal with callbacks.
// ----------------------------------------------------------------------

/**
* This implementation is used to receive callbacks from the remote
* service.
*/
private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
/**
* This is called by the remote service regularly to tell us about
* new values.  Note that IPC calls are dispatched through a thread
* pool running in each process, so the code executing here will
* NOT be running in our main thread like most other things -- so,
* to update the UI, we need to use a Handler to hop over there.
*/
public void valueChanged(int value) {
mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));
}
};

private static final int BUMP_MSG = 1;

private Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case BUMP_MSG:
mCallbackText.setText("Received from service: " + msg.arg1);
break;
default:
super.handleMessage(msg);
}
}

};
}


6)解绑Service

客户端调用 unbindService (ServiceConnection conn)方法即可。

以上就是Service的基本介绍,如有错误,还请指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: