第七章:Android Service组件

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);
			}
		});
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值