Service是Android系统提供的四种组件之一,它的地位和Activity是并列的,只不过没有Activity的使用频率高。顾名思义service就是运行在后台的一种服务程序,一般很少和用户交互,因此没有可视化界面。
定义一个Service类比较简单,只要继承Service类,实现其生命周期中的方法就可以了。一个定义好多Service必须在AndroidManifest.xml配置文件中通过<service>元素声明才能使用。
Service有自己的生命周期,我们可以调用startService()启动一个Service或者使用bindService()方法来绑定一个存在的Service,还可以通过RPC(远程进程调用)机制来实现不同进程间Service的调用。
一、Service简介
1、创建一个Service
创建一个Service类比较简单,只要定义一个类继承Service,覆盖该类中响应的方法就可以了。Service中定义了一些列和自身生命周期相关的方法,这些方法有:
- onBind(Intent intent):是必须实现的一个方法,返回一个绑定的接口给Service。
- onCreate():第一次被创建时,由系统调用。
- onStart(Intent intent,int startId):当通过startService()方法启动Service时,该方法被调用。
- onDestroy():当Service不再使用,系统调用该方法。
下面演示如何创建一个Service
/**
* 测试Service
*/
public class MyService extends Service {
//可以返回null,通常返回一个有aidl定义的接口
@Override
public IBinder onBind(Intent intent) {
Log.i("SERVICE", "onBinid......");
Toast.makeText(MyService.this, "onBinid......", Toast.LENGTH_SHORT).show();
return null;
}
//创建时调用
@Override
public void onCreate() {
Log.i("SERVICE", "onCreate......");
Toast.makeText(MyService.this, "onCreate......", Toast.LENGTH_SHORT).show();
}
//当客户端调用startService()方法启动Service时,该方法被调用
@Override
public void onStart(Intent intent, int startId) {
Log.i("SERVICE", "onStart......");
Toast.makeText(MyService.this, "onStart......", Toast.LENGTH_SHORT).show();
}
//当Service不再使用时调用
@Override
public void onDestroy() {
Log.i("SERVICE", "onDestroy......");
Toast.makeText(MyService.this, "onDestroy......", Toast.LENGTH_SHORT).show();
}
}
要想使用该Service必须在AndroidManifest.xml配置文件中使用<service>元素声明该Service。在<service>元素中添加<intent-filter>指定如何访问该Service。
<service android:name="MyRemoteService">
<intent-filter>
<action android:name="mx.android.ch07.MY_REMOTE_SERVICE"/>
</intent-filter>
</service>
2、启动和停止Service
//创建Intent
Intent intent = new Intent();
//设置Action属性
intent.setAction("mx.android.ch07.MY_SERVICE");
//启动该Service
startService(intent);
//停止Service
stopService(intent);
3、绑定一个已经存在的Service
绑定Service需要三个参数:bindService(intent, conn, Service.BIND_AUTO_CREATE);第一个是Intent;第二个是ServiceConnection对象,我们创建该对象实现其onServiceConnected()和onServiceDisConnected()方法来判断连接成功或者断开连接;第三个是如何创建Service,一般指定绑定时自动创建。
private ServiceConnection conn = new ServiceConnection() {
@Override//连接时调用
public void onServiceConnected(ComponentName name, IBinder service) {
//输出日志
Log.i("SERVICE","连接成功!");
//通过Toast显示信息
Toast.makeText(Test_Service.this, "连接成功!", Toast.LENGTH_SHORT).show();
}
@Override//断开时调用
public void onServiceDisconnected(ComponentName name) {
Log.i("SERVICE","断开连接!");
Toast.makeText(Test_Service.this, "断开连接!", Toast.LENGTH_SHORT).show();
}
};
bindService(intent, conn, Service.BIND_AUTO_CREATE);
4、Service实例演示
下面通过一个实例演示如何创建、启动、停止及绑定一个Service。
创建Activity,在该类的顶部声明四个Button对象,分别用来启动、停止、绑定和解除绑定Service
public class Test_Service extends Activity {
private Button startBtn,stopBtn,bindBtn,unbindBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startBtn = (Button) findViewById(R.id.startService);
stopBtn = (Button) findViewById(R.id.stopService);
bindBtn = (Button) findViewById(R.id.bindService);
unbindBtn = (Button) findViewById(R.id.unbindService);
startBtn.setOnClickListener(startListener);
stopBtn.setOnClickListener(stopListener);
bindBtn.setOnClickListener(bindListener);
unbindBtn.setOnClickListener(unbindListener);
}
private OnClickListener startListener = new OnClickListener() {
@Override
public void onClick(View v) {
//创建Intent
Intent intent = new Intent();
//设置Action属性
intent.setAction("mx.android.ch07.MY_SERVICE");
//启动该Service
startService(intent);
}
};
private OnClickListener stopListener = new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("mx.android.ch07.MY_SERVICE");
stopService(intent);
}
};
private OnClickListener bindListener = new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("mx.android.ch07.MY_SERVICE");
bindService(intent, conn, Service.BIND_AUTO_CREATE);
}
};
private OnClickListener unbindListener = new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("mx.android.ch07.MY_SERVICE");
unbindService(conn);
}
};
//连接对象
private ServiceConnection conn = new ServiceConnection() {
@Override//连接时调用
public void onServiceConnected(ComponentName name, IBinder service) {
//输出日志
Log.i("SERVICE","连接成功!");
//通过Toast显示信息
Toast.makeText(Test_Service.this, "连接成功!", Toast.LENGTH_SHORT).show();
}
@Override//断开时调用
public void onServiceDisconnected(ComponentName name) {
Log.i("SERVICE","断开连接!");
Toast.makeText(Test_Service.this, "断开连接!", Toast.LENGTH_SHORT).show();
}
};
}
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/startService"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="启动Service" />
<Button
android:id="@+id/stopService"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="停止Service" />
<Button
android:id="@+id/bindService"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="绑定Service" />
<Button
android:id="@+id/unbindService"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="解除绑定Service" />
</LinearLayout>
创建一个类继承Service,覆盖其生命周期中的方法,并在各个方法中显示信息。
public class MyService extends Service {
//可以返回null,通常返回一个有aidl定义的接口
@Override
public IBinder onBind(Intent intent) {
Log.i("SERVICE", "onBinid......");
Toast.makeText(MyService.this, "onBinid......", Toast.LENGTH_SHORT).show();
return null;
}
//创建时调用
@Override
public void onCreate() {
Log.i("SERVICE", "onCreate......");
Toast.makeText(MyService.this, "onCreate......", Toast.LENGTH_SHORT).show();
}
//当客户端调用startService()方法启动Service时,该方法被调用
@Override
public void onStart(Intent intent, int startId) {
Log.i("SERVICE", "onStart......");
Toast.makeText(MyService.this, "onStart......", Toast.LENGTH_SHORT).show();
}
//当Service不再使用时调用
@Override
public void onDestroy() {
Log.i("SERVICE", "onDestroy......");
Toast.makeText(MyService.this, "onDestroy......", Toast.LENGTH_SHORT).show();
}
}
在AndroidManifest.xml配置文件中声明Activity和Service
<service android:name="MyService">
<intent-filter>
<action android:name="mx.android.ch07.MY_SERVICE"/>
</intent-filter>
</service>
二、远程Service调用
1、创建一个AIDL文件
定义一个AIDL文件的语法和定义一个Java接口的语法相似,只不过文件扩展名是“.aidl”。在AIDL文件中可以声明任意多个方法,方法可以带参数也可以有返回值,参数和返回值可以是任意类型。需要注意的是,你必须除了导入内建类型(int、boolean等)外的任何其他类型,即使它们在同一个包中。具体规则如下:
- Java原始类型不需要导入
- String、List、Map和CharSequence不需要导入
定义好的AIDL文件可以使用Android SDK - Tool下面的AIDL工具生成Java代码,如果使用基于Eclipse的ADT插件,代码会自动生成。下面我们使用Eclipse的ADT插件创建一个IPerson.aidl文件。
IPerson.aidl
interface IPerson{
void setAge(int age);
void setName(String name);
String display();
}
当我们创建好上述文件后,刷新该文件系统自动在gen目录下响应的包中创建了一个Java实现接口。
IPerson.java
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: E:\\Android\\workspace\\MyAndroidPrj_ch07\\src\\mx\\android\\ch07\\IPerson.aidl
*/
package mx.android.ch07;
public interface IPerson extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements mx.android.ch07.IPerson
{
private static final java.lang.String DESCRIPTOR = "mx.android.ch07.IPerson";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an mx.android.ch07.IPerson interface,
* generating a proxy if needed.
*/
public static mx.android.ch07.IPerson asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof mx.android.ch07.IPerson))) {
return ((mx.android.ch07.IPerson)iin);
}
return new mx.android.ch07.IPerson.Stub.Proxy(obj);
}
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_setAge:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
this.setAge(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_setName:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
this.setName(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_display:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.display();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements mx.android.ch07.IPerson
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
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();
}
}
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();
}
}
public java.lang.String display() 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_display, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_setAge = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_setName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_display = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
}
public void setAge(int age) throws android.os.RemoteException;
public void setName(java.lang.String name) throws android.os.RemoteException;
public java.lang.String display() throws android.os.RemoteException;
}
认真分析上述代码,我们会发现它是使用代理模式来实现的。我们一般是定义该接口的静态内部类Stub的asInterface()方法,返回我们的接口。
2、实现AIDL文件生成的Java接口
AIDL会生成一个和.aidl文件名同名的Java接口文件,该接口中有一个静态抽象内部类Stub,该类中声明了AIDL文件中定义的所有方法。其中有一个重要的方法是asInterface(),该方法通过代理模式返回Java接口的实现。
我们可以定义一个实现类,该类继承Stub,实现我们定义的三个方法。
/**
* 实现AIDL文件生成的Java接口
* IPerson接口实现类
*/
public class IPersonImpl extends IPerson.Stub {
//声明两个变量
private int age;
private String name;
//设置age
@Override
public void setAge(int age) throws RemoteException {
this.age = age;
}
//设置name
@Override
public void setName(String name) throws RemoteException {
this.name = name;
}
//显示name和age
@Override
public String display() throws RemoteException {
return "name:" + name + ",age:" + age;
}
}
3、将你的接口暴露给客户端
在Service的onBind()方法中返回该接口,当我们版定该接口时调用该方法。
public class MyRemoteService extends Service {
//声明IPerson接口
private Stub iPerson = new IPersonImpl();
@Override
public IBinder onBind(Intent intent) {
return iPerson;
}
}
4、客户端调用
定义一个Activity来绑定远程Service,获得IPerson接口,通过RPC机制调用接口中的方法。
public class MainActivity extends Activity{
private IPerson iPerson;
private Button btn;
//实例化ServiceConnection
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获得IPerson接口
iPerson = IPerson.Stub.asInterface(service);
if(iPerson != null){
try {
//RPC方法调用
iPerson.setName("张三");
iPerson.setAge(20);
String msg = iPerson.display();
//显示方法调用返回值
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainactivity);
btn = (Button) findViewById(R.id.mainActivityButton);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent();
intent.setAction("mx.android.ch07.MY_REMOTE_SERVICE");
//绑定服务
bindService(intent, conn, Service.BIND_AUTO_CREATE);
}
});
}
}